Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- {
- "/logs/app_2025-03-16T14-50-54.242Z.log": {
- "Path": "/logs/app_2025-03-16T14-50-54.242Z.log",
- "SizeKB": "0,10"
- },
- "/logs/server_2025-04-16T15-33-05.987Z.log": {
- "Path": "/logs/server_2025-04-16T15-33-05.987Z.log",
- "SizeKB": "5,25"
- },
- "/logs/debug_2025-03-16T15-02-19.600Z.log": {
- "Path": "/logs/debug_2025-03-16T15-02-19.600Z.log",
- "SizeKB": "10,74"
- },
- "/server/controllers/serverManager.js": {
- "Content": "const fs = require('fs').promises;\r\nconst path = require('path');\r\nconst { spawn } = require('child_process');\r\nconst { log } = require('../utils/logger');\r\nconst { createDefaultInstance } = require('../utils/helpers');\r\n\r\nconst servers = {};\r\nlet wss;\r\nconst instancesPath = path.join(__dirname, '../instances.json');\r\n\r\nfunction setWss(webSocketServer) {\r\n wss = webSocketServer;\r\n}\r\n\r\n// Funkcja do tworzenia pliku eula.txt z eula=true\r\nasync function createEulaFile(serverDir) {\r\n const eulaPath = path.join(serverDir, 'eula.txt');\r\n const eulaContent = `#By changing the setting below to TRUE you are indicating your agreement to our EULA (https://account.mojang.com/documents/minecraft_eula).\\neula=true\\n`;\r\n try {\r\n await fs.writeFile(eulaPath, eulaContent);\r\n log('server', 'info', `[EULA_CREATE] Utworzono eula.txt w ${serverDir} z eula=true, zajebi艣cie! 馃敟`);\r\n } catch (e) {\r\n log('error', 'error', `[EULA_CREATE_ERROR] B艂膮d przy tworzeniu eula.txt w ${serverDir}: ${e.message}`);\r\n }\r\n}\r\n\r\nasync function initServers() {\r\n log('server', 'info', '[SERVERS_INIT] Inicjalizacja listy serwer贸w...');\r\n const serversDir = path.join(__dirname, '../servers');\r\n await fs.mkdir(serversDir, { recursive: true }).catch(() => log('server', 'info', '[SERVERS_DIR] Katalog servers ju偶 istnieje'));\r\n\r\n await fs.mkdir(path.dirname(instancesPath), { recursive: true });\r\n let instancesData;\r\n try {\r\n const rawData = await fs.readFile(instancesPath, 'utf8');\r\n instancesData = JSON.parse(rawData);\r\n } catch (e) {\r\n log('server', 'warn', '[INSTANCES_READ] Brak pliku instances.json, tworzenie nowego');\r\n instancesData = { servers: {} };\r\n await fs.writeFile(instancesPath, JSON.stringify(instancesData, null, 2));\r\n }\r\n\r\n const dirs = await fs.readdir(serversDir).catch((e) => {\r\n log('error', 'error', '[SERVERS_READ_ERROR] B艂膮d odczytu katalogu servers', e);\r\n return [];\r\n });\r\n\r\n for (const dir of dirs) {\r\n try {\r\n const stats = await fs.stat(path.join(serversDir, dir));\r\n if (!stats.isDirectory()) continue;\r\n\r\n let instance = instancesData.servers[dir];\r\n if (!instance) {\r\n log('server', 'warn', `[SERVERS_LOAD_WARN] Brak instancji dla ${dir}, tworzenie domy艣lnej`);\r\n instance = createDefaultInstance(dir);\r\n instancesData.servers[dir] = instance;\r\n }\r\n\r\n servers[dir] = { \r\n ...instance, \r\n process: null, \r\n running: false,\r\n mcVersion: instance.mcVersion || instance.version || null\r\n };\r\n await loadServerFiles(dir);\r\n\r\n // Sprawdzamy, czy eula.txt istnieje, je艣li nie, to tworzymy\r\n const serverDir = path.join(serversDir, dir);\r\n try {\r\n await fs.access(path.join(serverDir, 'eula.txt'));\r\n } catch {\r\n await createEulaFile(serverDir);\r\n }\r\n\r\n log('server', 'info', `[SERVERS_LOADED] Wczytano serwer: ${dir}`);\r\n } catch (e) {\r\n log('error', 'error', `[SERVERS_LOAD_ERROR] B艂膮d przetwarzania serwera ${dir}`, e);\r\n }\r\n }\r\n\r\n await saveInstances(instancesData);\r\n}\r\n\r\nasync function addServer(name) {\r\n log('server', 'info', `[SERVER_ADD] Dodawanie serwera: ${name}`);\r\n const dir = path.join(__dirname, '../servers', name);\r\n await fs.mkdir(dir, { recursive: true }).catch(() => log('server', 'info', `[SERVER_DIR] Katalog ${name} ju偶 istnieje`));\r\n \r\n // Tworzymy eula.txt z eula=true\r\n await createEulaFile(dir);\r\n\r\n const instance = createDefaultInstance(name);\r\n servers[name] = { \r\n ...instance, \r\n process: null, \r\n running: false, \r\n mcVersion: null\r\n };\r\n await loadServerFiles(name);\r\n\r\n const instancesData = await loadInstances();\r\n instancesData.servers[name] = { ...servers[name], process: null, running: false };\r\n await saveInstances(instancesData);\r\n broadcastServers();\r\n}\r\n\r\nasync function deleteServer(serverName) {\r\n if (!servers[serverName] || servers[serverName].running) {\r\n log('error', 'error', `[SERVER_DELETE_ERROR] Serwer ${serverName} dzia艂a lub nie istnieje`);\r\n return;\r\n }\r\n const serverDir = path.join(__dirname, '../servers', serverName);\r\n try {\r\n await fs.rm(serverDir, { recursive: true, force: true });\r\n delete servers[serverName];\r\n\r\n const instancesData = await loadInstances();\r\n delete instancesData.servers[serverName];\r\n await saveInstances(instancesData);\r\n\r\n log('server', 'info', `[SERVER_DELETED] Usuni臋to serwer: ${serverName}, zajebi艣cie! 馃敟`);\r\n broadcastServers();\r\n } catch (e) {\r\n log('error', 'error', `[SERVER_DELETE_ERROR] B艂膮d przy usuwaniu ${serverName}: ${e}`);\r\n }\r\n}\r\n\r\nasync function loadServerFiles(serverName) {\r\n const server = servers[serverName];\r\n server.files = server.files || {};\r\n const files = ['banned-ips.json', 'banned-players.json', 'ops.json', 'whitelist.json'];\r\n for (const file of files) {\r\n try {\r\n server.files[file] = await fs.readFile(path.join(server.dir, file), 'utf8');\r\n } catch {\r\n server.files[file] = '[]';\r\n await fs.writeFile(path.join(server.dir, file), '[]');\r\n }\r\n }\r\n try {\r\n await fs.access(path.join(server.dir, 'mods'));\r\n server.hasMods = true;\r\n server.mods = await fs.readdir(path.join(server.dir, 'mods')).catch(() => []);\r\n } catch {\r\n server.hasMods = false;\r\n server.mods = [];\r\n await fs.mkdir(path.join(server.dir, 'mods'), { recursive: true });\r\n }\r\n}\r\n\r\nasync function startServer(serverName, ws) {\r\n const server = servers[serverName];\r\n if (!server.jar) {\r\n log('error', 'error', `[SERVER_START_ERROR] Brak pliku JAR dla ${serverName}`);\r\n return;\r\n }\r\n if (server.running) {\r\n log('error', 'error', `[SERVER_START_ERROR] Serwer ${serverName} ju偶 dzia艂a`);\r\n return;\r\n }\r\n const javaPath = `\"${server.javaPath || 'java'}\"`;\r\n const jarPath = `\"${path.join(server.dir, server.jar)}\"`;\r\n const args = [`-Xmx${server.ram}G`, ...(server.javaParams ? server.javaParams.split(' ') : []), '-jar', jarPath, 'nogui'];\r\n log('minecraft', 'info', `[SERVER_RUNNING] Uruchamianie serwera ${serverName} z Java: ${javaPath}, args: ${args.join(' ')}`);\r\n\r\n try {\r\n await fs.access(path.join(server.dir, server.jar));\r\n } catch (e) {\r\n log('error', 'error', `[SERVER_START_ERROR] Kurwa, nie ma dost臋pu do ${jarPath}!`, e);\r\n return;\r\n }\r\n\r\n const proc = spawn(javaPath, args, { cwd: server.dir, shell: true });\r\n server.process = proc;\r\n server.running = true;\r\n server.crashed = false;\r\n\r\n // Debugowanie RAM-u po starcie\r\n setTimeout(() => {\r\n if (proc.pid) {\r\n log('debug', 'info', `[SERVER_RAM_DEBUG] PID ${proc.pid} uruchomiony, sprawdzam RAM dla ${serverName}`);\r\n const memory = process.memoryUsage();\r\n log('debug', 'info', `[SERVER_RAM_DEBUG] Zu偶ycie RAM-u procesu: ${Math.round(memory.rss / 1024 / 1024)}MB`);\r\n }\r\n }, 5000); // Sprawdzamy po 5 sekundach\r\n\r\n proc.stdout.on('data', (data) => ws.send(JSON.stringify({ type: 'console', serverName, output: data.toString() })));\r\n proc.stderr.on('data', (data) => {\r\n const error = data.toString();\r\n log('error', 'error', `[SERVER_ERROR] B艂膮d Javy dla ${serverName}: ${error}`);\r\n ws.send(JSON.stringify({ type: 'console', serverName, output: error }));\r\n });\r\n proc.on('close', (code) => {\r\n server.running = false;\r\n server.crashed = code !== 0;\r\n server.process = null;\r\n log('minecraft', 'info', `[SERVER_STOPPED] Serwer ${serverName} zatrzymany z kodem ${code}`);\r\n broadcastServers();\r\n });\r\n\r\n await saveInstance(serverName);\r\n broadcastServers();\r\n}\r\n\r\nfunction stopServer(serverName) {\r\n const server = servers[serverName];\r\n if (!server.running || !server.process) return;\r\n server.process.stdin.write('stop\\n');\r\n server.running = false;\r\n}\r\n\r\nasync function restartServer(serverName, ws) {\r\n stopServer(serverName);\r\n await new Promise(resolve => setTimeout(resolve, 1000));\r\n await startServer(serverName, ws);\r\n}\r\n\r\nfunction killServer(serverName) {\r\n const server = servers[serverName];\r\n if (!server.running || !server.process) return;\r\n server.process.kill('SIGKILL');\r\n server.running = false;\r\n}\r\n\r\nasync function uploadJar(serverName, data, filename) {\r\n if (!servers[serverName]) {\r\n log('error', 'error', `[JAR_UPLOAD_ERROR] Serwer ${serverName} nie istnieje, kurwa! 馃槨`);\r\n return;\r\n }\r\n\r\n const serverDir = servers[serverName].dir;\r\n const jarPath = path.join(serverDir, filename);\r\n\r\n try {\r\n const base64Data = data.replace(/^data:application\\/octet-stream;base64,/, '');\r\n const binaryData = Buffer.from(base64Data, 'base64');\r\n await fs.writeFile(jarPath, binaryData);\r\n log('debug', 'info', `[JAR_UPLOAD_DEBUG] ZAPISANO JAR W: ${jarPath}`);\r\n\r\n servers[serverName].jar = filename;\r\n await saveInstance(serverName);\r\n\r\n broadcastServers();\r\n log('info', 'info', `[JAR_UPLOAD_SUCCESS] JAR ${filename} zapisany dla ${serverName}, zajebi艣cie! 馃敟`);\r\n } catch (e) {\r\n log('error', 'error', `[JAR_UPLOAD_ERROR] B艂膮d zapisu JAR dla ${serverName}: ${e.message}`);\r\n }\r\n}\r\n\r\nasync function loadInstances() {\r\n try {\r\n const rawData = await fs.readFile(instancesPath, 'utf8');\r\n return JSON.parse(rawData);\r\n } catch (e) {\r\n log('server', 'warn', '[INSTANCES_READ] Brak pliku instances.json, tworzenie nowego');\r\n return { servers: {} };\r\n }\r\n}\r\n\r\nasync function saveInstances(instancesData) {\r\n await fs.writeFile(instancesPath, JSON.stringify(instancesData, null, 2));\r\n log('minecraft', 'info', '[INSTANCES_SAVED] Zaktualizowano instances.json');\r\n}\r\n\r\nasync function saveInstance(serverName) {\r\n const server = servers[serverName];\r\n if (!server) {\r\n log('error', 'error', `[INSTANCE_SAVE_ERROR] Serwer ${serverName} nie istnieje, kurwa!`);\r\n return;\r\n }\r\n const instance = { \r\n ...server, \r\n process: null,\r\n running: false\r\n };\r\n const instancesData = await loadInstances();\r\n instancesData.servers[serverName] = instance;\r\n await saveInstances(instancesData);\r\n}\r\n\r\nfunction broadcastServers() {\r\n if (!wss) {\r\n log('error', 'error', '[SERVERS_BROADCAST_ERROR] WebSocket Server nie zainicjalizowany!');\r\n return;\r\n }\r\n wss.clients.forEach(client => {\r\n if (client.readyState === WebSocket.OPEN) {\r\n client.send(JSON.stringify({ type: 'servers', servers }));\r\n }\r\n });\r\n log('server', 'info', '[SERVERS_BROADCAST] Rozsy艂anie stanu serwer贸w do klient贸w');\r\n}\r\n\r\nfunction getRunningServers() {\r\n const running = Object.entries(servers)\r\n .filter(([_, server]) => server.running && server.process && server.process.pid)\r\n .map(([id, server]) => {\r\n log('server', 'debug', `[RUNNING_SERVERS_DEBUG] Serwer ${id}: PID ${server.process.pid}, running: ${server.running}`);\r\n return { id, pid: server.process.pid };\r\n });\r\n log('server', 'debug', `[RUNNING_SERVERS] Zwr贸cono ${running.length} dzia艂aj膮cych serwer贸w`);\r\n return running;\r\n}\r\n\r\nmodule.exports = {\r\n servers,\r\n setWss,\r\n initServers,\r\n addServer,\r\n deleteServer,\r\n loadServerFiles,\r\n startServer,\r\n stopServer,\r\n restartServer,\r\n killServer,\r\n uploadJar,\r\n saveInstance,\r\n broadcastServers,\r\n getRunningServers\r\n};",
- "Path": "/server/controllers/serverManager.js",
- "SizeKB": "11,66"
- },
- "/logs/app_2025-03-16T14-19-43.410Z.log": {
- "Path": "/logs/app_2025-03-16T14-19-43.410Z.log",
- "SizeKB": "0,10"
- },
- "/logs/minecraft_2025-03-16T15-02-19.600Z.log": {
- "Path": "/logs/minecraft_2025-03-16T15-02-19.600Z.log",
- "SizeKB": "0,24"
- },
- "/logs/app_2025-03-16T15-02-19.600Z.log": {
- "Path": "/logs/app_2025-03-16T15-02-19.600Z.log",
- "SizeKB": "0,10"
- },
- "/server/controllers/javaManager.js": {
- "Content": "const fs = require('fs').promises;\r\nconst path = require('path');\r\nconst { spawn } = require('child_process');\r\nconst https = require('https');\r\nconst { log } = require('../utils/logger');\r\n\r\nlet javaVersions = [];\r\nconst javaConfigPath = path.join(__dirname, '../java-config.json');\r\nlet isScanning = false; // Flaga przeciwko zap臋tleniom\r\n\r\nasync function initJava(config) {\r\n log('server', 'info', '[JAVA_INIT] Inicjalizacja konfiguracji Java...');\r\n await fs.mkdir(path.join(__dirname, '../javas'), { recursive: true });\r\n\r\n try {\r\n const configData = await fs.readFile(javaConfigPath, 'utf8');\r\n javaVersions = JSON.parse(configData);\r\n log('server', 'info', `[JAVA_CONFIG_READ] Wczytano wersje Java z konfiguracji: ${javaVersions.map(v => v.version).join(', ')}`);\r\n } catch (e) {\r\n log('server', 'warn', '[JAVA_CONFIG_READ] Brak pliku java-config.json lub b艂膮d parsowania, startujemy od zera');\r\n javaVersions = [];\r\n }\r\n\r\n const systemVersions = await checkSystemJava();\r\n systemVersions.forEach(v => {\r\n if (!javaVersions.some(jv => jv.version === v.version)) {\r\n javaVersions.push(v);\r\n log('server', 'info', `[JAVA_FOUND] Dodano systemow膮 wersj臋 Java: ${v.version}`);\r\n }\r\n });\r\n\r\n const localVersions = await scanJavaVersions();\r\n log('debug', 'info', `[JAVA_LOCAL_VERSIONS] Zescannowane lokalne wersje: ${JSON.stringify(localVersions)}`);\r\n localVersions.forEach(v => {\r\n if (!javaVersions.some(jv => jv.version === v.version)) {\r\n javaVersions.push(v);\r\n log('server', 'info', `[JAVA_FOUND] Dodano lokaln膮 wersj臋 Java: ${v.version}`);\r\n }\r\n });\r\n\r\n log('debug', 'info', `[JAVA_VERSIONS_PRE_SAVE] Stan javaVersions przed zapisem: ${JSON.stringify(javaVersions)}`);\r\n if (javaVersions.length === 0 && config.javaToDownload) {\r\n log('server', 'info', '[JAVA_DOWNLOAD_START] Nie znaleziono wersji Java, pobieranie domy艣lnych...');\r\n for (const version of config.javaToDownload) {\r\n await downloadJava(version);\r\n }\r\n javaVersions = await scanJavaVersions();\r\n }\r\n\r\n await saveJavaConfig();\r\n log('debug', 'info', `[JAVA_VERSIONS_POST_INIT] Ko艅cowy stan javaVersions: ${JSON.stringify(javaVersions)}`);\r\n}\r\n\r\nasync function checkSystemJava() {\r\n const versions = [];\r\n try {\r\n const javaCheck = spawn('java', ['-version'], { shell: true });\r\n return new Promise((resolve) => {\r\n javaCheck.stderr.on('data', (data) => {\r\n const version = data.toString().match(/version \"(.+?)\"/)?.[1];\r\n if (version) {\r\n versions.push({ version: `java-${version}`, path: 'java' });\r\n }\r\n });\r\n javaCheck.on('close', () => resolve(versions));\r\n });\r\n } catch (e) {\r\n log('error', 'error', '[JAVA_ERROR] B艂膮d podczas sprawdzania systemowej Java', e);\r\n return versions;\r\n }\r\n}\r\n\r\nasync function downloadJava(version) {\r\n const url = `https://api.adoptium.net/v3/binary/latest/${version}/ga/windows/x64/jdk/hotspot/normal/adoptium`;\r\n const filePath = path.join(__dirname, '../javas', `java-${version}.zip`);\r\n log('server', 'info', `[JAVA_DOWNLOAD_${version}] Pobieranie Java ${version} dla Windows...`);\r\n\r\n const file = await fs.open(filePath, 'w');\r\n return new Promise((resolve, reject) => {\r\n https.get(url, (res) => {\r\n res.pipe(file.createWriteStream());\r\n res.on('end', async () => {\r\n file.close();\r\n await extractJava(filePath, version);\r\n resolve();\r\n });\r\n }).on('error', (e) => {\r\n log('error', 'error', `[JAVA_DOWNLOAD_ERROR] B艂膮d pobierania Java ${version}`, e);\r\n reject(e);\r\n });\r\n });\r\n}\r\n\r\nasync function extractJava(filePath, version) {\r\n const extractDir = path.join(__dirname, '../javas', `java-${version}`);\r\n await fs.mkdir(extractDir, { recursive: true });\r\n const unzip = spawn('powershell', ['Expand-Archive', '-Path', filePath, '-DestinationPath', extractDir], { shell: true });\r\n return new Promise((resolve) => {\r\n unzip.on('close', async (code) => {\r\n if (code === 0) {\r\n await fs.unlink(filePath);\r\n }\r\n resolve();\r\n });\r\n });\r\n}\r\n\r\nasync function scanJavaVersions() {\r\n if (isScanning) return javaVersions; // Blokada przed zap臋tleniem\r\n isScanning = true;\r\n const javaDir = path.join(__dirname, '../javas');\r\n try {\r\n const dirs = await fs.readdir(javaDir);\r\n const versions = [];\r\n for (const dir of dirs) {\r\n log('debug', 'info', `[JAVA_SCAN_DEBUG] Sprawdzam folder: ${dir}`);\r\n const javaPath = path.join(javaDir, dir, 'bin', 'java.exe');\r\n const exists = await fs.access(javaPath).then(() => true).catch(() => false);\r\n log('debug', 'info', `[JAVA_SCAN_DEBUG] 艢cie偶ka ${javaPath} - istnieje: ${exists}`);\r\n if (exists) {\r\n versions.push({ version: dir, path: path.resolve(javaPath) });\r\n }\r\n }\r\n log('server', 'info', `[JAVA_SCAN_RESULT] Znaleziono: ${versions.map(v => v.version).join(', ')}`);\r\n isScanning = false;\r\n return versions;\r\n } catch (e) {\r\n log('error', 'error', '[JAVA_SCAN_ERROR] B艂膮d skanowania katalogu javas:', e);\r\n isScanning = false;\r\n return [];\r\n }\r\n}\r\n\r\nasync function saveJavaConfig() {\r\n await fs.writeFile(javaConfigPath, JSON.stringify(javaVersions, null, 2));\r\n log('server', 'info', '[JAVA_CONFIG_SAVED] Zaktualizowano plik konfiguracyjny Java');\r\n}\r\n\r\nfunction getJavaVersions() {\r\n return javaVersions;\r\n}\r\n\r\nmodule.exports = {\r\n getJavaVersions,\r\n initJava,\r\n scanJavaVersions\r\n};",
- "Path": "/server/controllers/javaManager.js",
- "SizeKB": "5,76"
- },
- "/logs/server_2025-04-16T15-46-59.644Z.log": {
- "Path": "/logs/server_2025-04-16T15-46-59.644Z.log",
- "SizeKB": "13,03"
- },
- "/package.json": {
- "Content": "{\n \"dependencies\": {\n \"archiver\": \"^7.0.1\",\n \"express\": \"^4.21.2\",\n \"fs\": \"^0.0.1-security\",\n \"logger\": \"^0.0.1\",\n \"ws\": \"^8.18.1\"\n },\n \"name\": \"testowe-konta\",\n \"version\": \"1.0.0\",\n \"description\": \"\",\n \"main\": \"server.js\",\n \"scripts\": {\n \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n \"start\": \"node server.js\"\n },\n \"keywords\": [],\n \"author\": \"\",\n \"license\": \"ISC\",\n \"type\": \"commonjs\"\n}\n",
- "Path": "/package.json",
- "SizeKB": "0,42"
- },
- "/server/instances.json": {
- "Content": "{\n \"servers\": {\n \"test\": {\n \"name\": \"test\",\n \"dir\": \"C:\\\\Users\\\\Admin\\\\Desktop\\\\minecraft-server-manager\\\\server\\\\servers\\\\test\",\n \"jar\": \"server-1.12.2.jar\",\n \"java\": \"jre-legacy\",\n \"javaPath\": \"C:\\\\Users\\\\Admin\\\\Desktop\\\\minecraft-server-manager\\\\server\\\\javas\\\\jre-legacy\\\\bin\\\\java.exe\",\n \"ram\": 11,\n \"version\": null,\n \"process\": null,\n \"running\": false,\n \"properties\": {\n \"motd\": \"Serwer MC\",\n \"difficulty\": \"normal\",\n \"pvp\": \"false\",\n \"max-players\": \"20\",\n \"online-mode\": \"true\"\n },\n \"files\": {\n \"banned-ips.json\": \"[]\",\n \"banned-players.json\": \"[]\",\n \"ops.json\": \"[\\n {\\n \\\"uuid\\\": \\\"dbeac262-3a10-44c9-aab6-18e7ec523d5b\\\",\\n \\\"name\\\": \\\"Paffcio94\\\",\\n \\\"level\\\": 4,\\n \\\"bypassesPlayerLimit\\\": false\\n },\\n {\\n \\\"uuid\\\": \\\"4dc4bd49-2a19-4f96-b2db-d98d79766d22\\\",\\n \\\"name\\\": \\\"PaFFcio\\\",\\n \\\"level\\\": 4,\\n \\\"bypassesPlayerLimit\\\": false\\n }\\n]\",\n \"whitelist.json\": \"[]\"\n },\n \"hasMods\": true,\n \"mods\": [],\n \"mcVersion\": \"1.12.2\",\n \"crashed\": false\n }\n }\n}",
- "Path": "/server/instances.json",
- "SizeKB": "1,12"
- },
- "/logs/app_2025-04-16T15-40-49.225Z.log": {
- "Path": "/logs/app_2025-04-16T15-40-49.225Z.log",
- "SizeKB": "0,10"
- },
- "/logs/debug_2025-03-16T14-48-18.664Z.log": {
- "Path": "/logs/debug_2025-03-16T14-48-18.664Z.log",
- "SizeKB": "25,69"
- },
- "/logs/minecraft_2025-04-16T15-40-49.225Z.log": {
- "Path": "/logs/minecraft_2025-04-16T15-40-49.225Z.log",
- "SizeKB": "0,08"
- },
- "/logs/app.log": {
- "Path": "/logs/app.log",
- "SizeKB": "0,68"
- },
- "/logs/app_2025-03-16T15-00-13.680Z.log": {
- "Path": "/logs/app_2025-03-16T15-00-13.680Z.log",
- "SizeKB": "0,41"
- },
- "/public/js/ui.js": {
- "Content": "import { sendMessage, currentServer } from './websocket.js';\r\nimport { updateJava } from './java.js'; // Importujemy z java.js\r\n\r\nexport function initUI() {\r\n const tabs = document.querySelectorAll('.tab');\r\n tabs.forEach(tab => {\r\n tab.addEventListener('click', () => {\r\n tabs.forEach(t => t.classList.remove('active'));\r\n document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));\r\n tab.classList.add('active');\r\n document.getElementById(`${tab.dataset.tab}Tab`).classList.add('active');\r\n if (tab.dataset.tab === 'files' && currentServer) {\r\n sendMessage({ type: 'getFiles', serverName: currentServer, path: '' });\r\n } else if (tab.dataset.tab === 'java' && currentServer) {\r\n updateJava(currentServer); // Poprawnie wywo艂ujemy\r\n } else if (tab.dataset.tab === 'logs' && currentServer) {\r\n sendMessage({ type: 'getLog', serverName: currentServer, logFile: document.getElementById('logSelect').value });\r\n }\r\n console.log(`Prze艂膮czono na: ${tab.dataset.tab}, zajebi艣cie! 馃榿`);\r\n });\r\n });\r\n tabs[0]?.click(); // Domy艣lna zak艂adka\r\n}\r\n\r\nexport function updateLogs(logContent) {\r\n const logsDiv = document.getElementById('logs');\r\n logsDiv.textContent = logContent || 'Brak log贸w, kurwa ma膰! 馃槩';\r\n logsDiv.scrollTop = logsDiv.scrollHeight; // Auto-scroll na d贸艂\r\n}",
- "Path": "/public/js/ui.js",
- "SizeKB": "1,45"
- },
- "/logs/minecraft_2025-03-16T14-48-18.664Z.log": {
- "Path": "/logs/minecraft_2025-03-16T14-48-18.664Z.log",
- "SizeKB": "0,77"
- },
- "/logs/error_2025-04-16T15-46-59.644Z.log": {
- "Path": "/logs/error_2025-04-16T15-46-59.644Z.log",
- "SizeKB": "0,40"
- },
- "/logs/debug_2025-03-16T14-19-43.410Z.log": {
- "Path": "/logs/debug_2025-03-16T14-19-43.410Z.log",
- "SizeKB": "21,21"
- },
- "/public/js/files.js": {
- "Content": "import { sendMessage, currentServer, setUpdateCallbacks } from './websocket.js';\r\n\r\nexport function initFiles() {\r\n document.getElementById('jarUpload').addEventListener('change', uploadJar);\r\n\r\n setUpdateCallbacks({\r\n updateFileList: (path, files) => {\r\n const list = document.getElementById('fileList');\r\n list.innerHTML = '';\r\n if (path) {\r\n const back = document.createElement('div');\r\n back.className = 'file-item';\r\n back.textContent = '猬?Wr贸膰';\r\n back.dataset.path = path.split('/').slice(0, -1).join('/');\r\n back.dataset.isDir = 'true';\r\n back.addEventListener('click', () => openDir(back.dataset.path));\r\n back.addEventListener('contextmenu', (e) => showFileContext(e));\r\n list.appendChild(back);\r\n }\r\n const sortedFiles = files.sort((a, b) => a.isDir === b.isDir ? a.name.localeCompare(b.name) : b.isDir ? 1 : -1);\r\n sortedFiles.forEach(file => {\r\n const div = document.createElement('div');\r\n div.className = 'file-item';\r\n div.textContent = `${file.isDir ? '馃搧' : '馃搫'} ${file.name}`;\r\n div.dataset.path = path ? `${path}/${file.name}` : file.name;\r\n div.dataset.isDir = file.isDir;\r\n if (file.isDir) div.addEventListener('click', () => openDir(div.dataset.path));\r\n div.addEventListener('contextmenu', (e) => showFileContext(e));\r\n list.appendChild(div);\r\n });\r\n }\r\n });\r\n}\r\n\r\nfunction uploadJar() {\r\n const file = document.getElementById('jarUpload').files[0];\r\n if (file && currentServer) {\r\n const reader = new FileReader();\r\n reader.onload = () => sendMessage({\r\n type: 'uploadJar',\r\n serverName: currentServer,\r\n data: reader.result,\r\n filename: file.name\r\n });\r\n reader.readAsDataURL(file);\r\n }\r\n}\r\n\r\nfunction openDir(path) {\r\n sendMessage({ type: 'getFiles', serverName: currentServer, path });\r\n}\r\n\r\nexport function showFileContext(event) {\r\n event.preventDefault();\r\n const target = event.target.closest('.file-item');\r\n if (!target) return;\r\n const path = target.dataset.path;\r\n const isDir = target.dataset.isDir === 'true';\r\n const menu = document.getElementById('fileContext');\r\n menu.innerHTML = `\r\n <div class=\"context-item\" data-action=\"rename\" data-path=\"${path}\">鉁忥笍 Zmie艅 nazw臋</div>\r\n <div class=\"context-item\" data-action=\"delete\" data-path=\"${path}\">馃棏锔?Usu艅</div>\r\n ${isDir ? `<div class=\"context-item\" data-action=\"openDir\" data-path=\"${path}\">馃搨 Otw贸rz</div>` : ''}\r\n `;\r\n menu.style.left = `${event.pageX}px`;\r\n menu.style.top = `${event.pageY}px`;\r\n menu.style.display = 'block';\r\n\r\n // Dodajemy obs艂ug臋 klikni臋膰 w menu kontekstowe\r\n menu.querySelectorAll('.context-item').forEach(item => {\r\n item.addEventListener('click', () => {\r\n const action = item.dataset.action;\r\n const path = item.dataset.path;\r\n if (action === 'rename') renameFile(path);\r\n if (action === 'delete') deleteFile(path);\r\n if (action === 'openDir') openDir(path);\r\n menu.style.display = 'none';\r\n });\r\n });\r\n\r\n document.addEventListener('click', () => menu.style.display = 'none', { once: true });\r\n}\r\n\r\nexport function renameFile(path) {\r\n const newName = prompt('Nowa nazwa:', path.split('/').pop());\r\n if (newName) sendMessage({ type: 'renameFile', serverName: currentServer, path, newName });\r\n}\r\n\r\nexport function deleteFile(path) {\r\n if (confirm('Na pewno usun膮膰?')) sendMessage({ type: 'deleteFile', serverName: currentServer, path });\r\n}",
- "Path": "/public/js/files.js",
- "SizeKB": "3,77"
- },
- "/public/js/backup.js": {
- "Content": "import { currentServer } from './websocket.js';\r\n\r\nexport class BackupHandler {\r\n constructor() {\r\n this.initButton();\r\n }\r\n\r\n initButton() {\r\n const button = document.getElementById('backup-btn');\r\n if (button) {\r\n button.addEventListener('click', () => this.createBackup());\r\n }\r\n }\r\n\r\n async createBackup() {\r\n if (!currentServer) {\r\n alert('Wybierz serwer przed utworzeniem kopii zapasowej!');\r\n return;\r\n }\r\n\r\n const button = document.getElementById('backup-btn');\r\n button.disabled = true;\r\n button.classList.add('loading');\r\n console.log(`Tworz臋 backup dla ${currentServer}, trzymaj piwo! 馃嵑`);\r\n\r\n try {\r\n const response = await fetch(`/backup/${currentServer}`);\r\n if (!response.ok) {\r\n throw new Error(`HTTP error! Status: ${response.status}`);\r\n }\r\n const result = await response.json();\r\n if (result.success) {\r\n alert(`Kopia zapasowa utworzona: ${result.path}`);\r\n console.log(`Backup zrobiony, zajebi艣cie! 馃敟 ${result.path}`);\r\n } else {\r\n throw new Error(result.error);\r\n }\r\n } catch (err) {\r\n console.error('B艂膮d backupu, kurwa ma膰!', err);\r\n alert(`Wyst膮pi艂 problem: ${err.message}`);\r\n } finally {\r\n button.disabled = false;\r\n button.classList.remove('loading');\r\n }\r\n }\r\n}",
- "Path": "/public/js/backup.js",
- "SizeKB": "1,50"
- },
- "/logs/error_2025-03-16T15-02-19.600Z.log": {
- "Path": "/logs/error_2025-03-16T15-02-19.600Z.log",
- "SizeKB": "0,42"
- },
- "/public/img/icon_96.png": {
- "Path": "/public/img/icon_96.png",
- "SizeKB": "2,99"
- },
- "/server/server.js": {
- "Content": "const express = require('express');\r\nconst WebSocket = require('ws');\r\nconst path = require('path');\r\nconst { initJava } = require('./controllers/javaManager');\r\nconst { initServers, broadcastServers, setWss, servers } = require('./controllers/serverManager');\r\nconst { handleWebSocket } = require('./controllers/wsHandler');\r\nconst { loadConfig } = require('./utils/configLoader');\r\nconst { log } = require('./utils/logger');\r\nconst os = require('os');\r\nconst ResourceMonitor = require('./controllers/resourceMonitor');\r\nconst BackupManager = require('./controllers/backupManager');\r\n\r\nconst app = express();\r\n\r\napp.use(express.static(path.join(__dirname, '../public')));\r\n\r\nconst getLocalIP = () => {\r\n const interfaces = os.networkInterfaces();\r\n for (const iface of Object.values(interfaces)) {\r\n for (const alias of iface) {\r\n if (alias.family === 'IPv4' && !alias.internal) {\r\n return alias.address;\r\n }\r\n }\r\n }\r\n return '127.0.0.1';\r\n};\r\n\r\nconst PORT = 8080;\r\nconst IP = getLocalIP();\r\nconst server = app.listen(PORT, () => {\r\n console.log(`Serwer uruchomiony na ${IP}:${PORT}`);\r\n log('server', 'info', `[START] Serwer uruchomiony na ${IP}:${PORT}`);\r\n});\r\n\r\nconst wss = new WebSocket.Server({ server });\r\n\r\nasync function init() {\r\n try {\r\n const config = await loadConfig();\r\n await Promise.all([initJava(config), initServers()]);\r\n setWss(wss);\r\n\r\n const resourceMonitor = new ResourceMonitor(\r\n { getRunningServers: () => Object.entries(servers).filter(([_, s]) => s.running).map(([id, s]) => ({ id, pid: s.process?.pid })) },\r\n { sendToAll: (data) => wss.clients.forEach(client => client.readyState === WebSocket.OPEN && client.send(JSON.stringify(data))) }\r\n );\r\n const backupManager = new BackupManager(\r\n { getServer: (id) => servers[id] }\r\n );\r\n\r\n resourceMonitor.startMonitoring();\r\n log('server', 'info', '[INIT_COMPLETE] Inicjalizacja zako艅czona, serwer gotowy');\r\n broadcastServers();\r\n\r\n app.get('/backup/:serverId', async (req, res) => {\r\n const serverId = req.params.serverId;\r\n try {\r\n if (!servers[serverId]) {\r\n throw new Error(`Serwer ${serverId} nie istnieje, kurwa!`);\r\n }\r\n const backupPath = await backupManager.createBackup(serverId);\r\n res.json({ success: true, path: backupPath });\r\n log('backup', 'info', `[BACKUP_SUCCESS] Utworzono kopi臋 zapasow膮 dla ${serverId}: ${backupPath}`);\r\n } catch (err) {\r\n res.status(500).json({ success: false, error: err.message });\r\n log('backup', 'error', `[BACKUP_ERROR] B艂膮d tworzenia kopii zapasowej dla ${serverId}`, err.message);\r\n }\r\n });\r\n } catch (e) {\r\n log('error', 'error', '[INIT_ERROR] B艂膮d inicjalizacji', e);\r\n }\r\n}\r\n\r\nwss.on('connection', (ws) => {\r\n log('server', 'info', '[CLIENT_CONNECT] Klient pod艂膮czony do panelu');\r\n handleWebSocket(ws);\r\n ws.on('close', () => log('server', 'info', '[CLIENT_DISCONNECT] Klient roz艂膮czony'));\r\n});\r\n\r\nwss.broadcast = (data) => {\r\n wss.clients.forEach((client) => {\r\n if (client.readyState === WebSocket.OPEN) {\r\n client.send(JSON.stringify(data));\r\n }\r\n });\r\n};\r\n\r\ninit();\r\nmodule.exports = { wss };",
- "Path": "/server/server.js",
- "SizeKB": "3,36"
- },
- "/public/js/java.js": {
- "Content": "import { sendMessage, sendDebouncedMessage, servers, currentServer, javaVersions, setUpdateCallbacks } from './websocket.js';\r\n\r\nconst debounce = (func, wait) => {\r\n let timeout;\r\n return (...args) => {\r\n clearTimeout(timeout);\r\n timeout = setTimeout(() => func(...args), wait);\r\n };\r\n};\r\n\r\nconst debouncedSetRam = debounce((serverName, ram) => {\r\n if (servers[serverName].ram !== parseInt(ram, 10)) {\r\n sendMessage({ type: 'setRam', serverName, ram });\r\n console.log(`Ustawiono RAM na ${ram}G dla ${serverName}, zajebi艣cie! 馃槑`);\r\n }\r\n}, 1000);\r\n\r\nexport function initJava() {\r\n console.log('Inicjalizacja java.js, kurwa startujemy! 馃敟');\r\n document.getElementById('jarUpload').addEventListener('change', uploadJar);\r\n const downloadBtn = document.getElementById('downloadBtn');\r\n if (downloadBtn) {\r\n downloadBtn.addEventListener('click', downloadJar);\r\n } else {\r\n console.log('Kurwa, brak downloadBtn w DOM, co艣 nie gra! 馃槨');\r\n }\r\n\r\n setUpdateCallbacks({\r\n updateJava: updateJava,\r\n updateJavaVersions: updateJavaVersions,\r\n updateVersionsList: updateVersionsList,\r\n handleDownloadProgress: handleDownloadProgress,\r\n handleDownloadComplete: handleDownloadComplete\r\n });\r\n\r\n // Nie wywo艂ujemy fetchVersions tutaj, zrobimy to w updateJava\r\n if (javaVersions.length > 0) {\r\n console.log('Mamy wersje Javy, aktualizuj臋:', javaVersions);\r\n updateJavaVersions();\r\n }\r\n}\r\n\r\nexport function updateJava(serverName) {\r\n console.log(`updateJava dla ${serverName}, sprawdzamy...`);\r\n if (!serverName || !servers[serverName]) {\r\n console.log(`Kurwa, serwer ${serverName} nie istnieje! 馃槨`);\r\n return;\r\n }\r\n\r\n const isRunning = servers[serverName].running;\r\n\r\n const versionPanel = document.getElementById('javaVersionPanel');\r\n versionPanel.innerHTML = '';\r\n const select = document.createElement('select');\r\n select.id = 'javaVersion';\r\n select.addEventListener('change', () => setJava(select.value));\r\n select.disabled = isRunning;\r\n versionPanel.appendChild(select);\r\n updateJavaVersions();\r\n\r\n if (isRunning) {\r\n const warning = document.createElement('div');\r\n warning.style.color = 'red';\r\n warning.textContent = 'Serwer dzia艂a, zatrzymaj go, 偶eby zmieni膰 Jav臋, kurwa! 馃槨';\r\n versionPanel.appendChild(warning);\r\n }\r\n\r\n const resourcesPanel = document.getElementById('javaResourcesPanel');\r\n resourcesPanel.innerHTML = '';\r\n const ramDiv = document.createElement('div');\r\n ramDiv.innerHTML = `\r\n <input type=\"range\" min=\"1\" max=\"32\" value=\"${servers[serverName].ram || 2}\" id=\"ram\" ${isRunning ? 'disabled' : ''}>\r\n <span>RAM: <span id=\"ramValue\">${servers[serverName].ram || 2}</span> GB</span>\r\n `;\r\n resourcesPanel.appendChild(ramDiv);\r\n const ramInput = document.getElementById('ram');\r\n ramInput.addEventListener('input', () => {\r\n document.getElementById('ramValue').textContent = ramInput.value;\r\n debouncedSetRam(serverName, ramInput.value);\r\n });\r\n\r\n const params = document.createElement('div');\r\n params.innerHTML = `\r\n <input type=\"text\" class=\"java-params\" placeholder=\"Dodatkowe parametry Javy (np. -Xms2G)\" value=\"${servers[serverName].javaParams || ''}\" ${isRunning ? 'disabled' : ''}>\r\n `;\r\n resourcesPanel.appendChild(params);\r\n const paramsInput = params.querySelector('.java-params');\r\n paramsInput.addEventListener('change', () => setJavaParams(paramsInput.value));\r\n\r\n const jarPanel = document.getElementById('javaJarPanel');\r\n const jarUpload = document.getElementById('jarUpload');\r\n jarUpload.disabled = isRunning;\r\n const currentJar = document.getElementById('currentJar');\r\n currentJar.textContent = servers[serverName].jar ? servers[serverName].jar : 'Nie wybrano pliku, kurwa! 馃槢';\r\n console.log(`Aktualny JAR dla ${serverName}: ${servers[serverName].jar || 'brak'}, dane z servers:`, servers[serverName]);\r\n\r\n // Blokada mened偶era pobierania, je艣li serwer dzia艂a\r\n const versionSelect = document.getElementById('versionSelect');\r\n if (versionSelect) {\r\n versionSelect.disabled = isRunning;\r\n } else {\r\n console.log('Kurwa, brak versionSelect w DOM, co艣 zjebane! 馃槨');\r\n }\r\n const downloadBtn2 = document.getElementById('downloadBtn');\r\n if (downloadBtn2) {\r\n downloadBtn2.disabled = isRunning;\r\n }\r\n\r\n // Pobierz wersje MC\r\n fetchVersions();\r\n}\r\n\r\nexport function updateJavaVersions() {\r\n console.log('updateJavaVersions, sprawdzamy wersje Javy...');\r\n const select = document.getElementById('javaVersion');\r\n if (!select) {\r\n console.log('Kurwa, brak javaVersion w DOM, nie aktualizuj臋! 馃槨');\r\n return;\r\n }\r\n select.innerHTML = '<option value=\"\">Wybierz wersj臋 Java</option>';\r\n javaVersions.forEach(v => {\r\n const option = document.createElement('option');\r\n option.value = v.path;\r\n option.textContent = v.version;\r\n if (v.path === servers[currentServer]?.javaPath) {\r\n option.selected = true;\r\n }\r\n select.appendChild(option);\r\n });\r\n console.log(`Wczytano Javy: ${javaVersions.map(v => v.version).join(', ')}, zajebi艣cie! 馃槑`);\r\n}\r\n\r\nfunction uploadJar() {\r\n console.log('uploadJar, wgrywamy s艂oik...');\r\n const file = document.getElementById('jarUpload').files[0];\r\n if (file && currentServer) {\r\n const reader = new FileReader();\r\n reader.onload = () => sendMessage({\r\n type: 'uploadJar',\r\n serverName: currentServer,\r\n data: reader.result,\r\n filename: file.name\r\n });\r\n reader.readAsDataURL(file);\r\n } else {\r\n console.log('Kurwa, brak pliku albo serwera, co jest?! 馃槨');\r\n }\r\n}\r\n\r\nfunction setJava(version) {\r\n console.log(`setJava, zmiana na wersj臋: ${version}`);\r\n if (currentServer && !servers[currentServer].running) {\r\n sendMessage({ type: 'setJava', serverName: currentServer, version });\r\n console.log(`Zmiana Javy na ${version} dla ${currentServer}, w chuj git! 馃敟`);\r\n } else if (servers[currentServer].running) {\r\n alert('Zatrzymaj serwer, zanim zmienisz Jav臋, kurwa! 馃槨');\r\n }\r\n}\r\n\r\nfunction setJavaParams(params) {\r\n console.log(`setJavaParams, nowe parametry: ${params}`);\r\n if (currentServer && !servers[currentServer].running) {\r\n sendMessage({ type: 'setJavaParams', serverName: currentServer, params });\r\n console.log(`Parametry Javy zmienione na ${params} dla ${currentServer}, elegancko! 馃憤`);\r\n }\r\n}\r\n\r\nfunction fetchVersions() {\r\n console.log('fetchVersions, pobieramy wersje MC...');\r\n if (currentServer) {\r\n sendMessage({ type: 'getVersions', serverName: currentServer });\r\n console.log(`Wys艂ano getVersions dla ${currentServer}, czekamy! 馃槑`);\r\n } else {\r\n console.log('Kurwa, brak currentServer, nie pobieram wersji! 馃槨');\r\n }\r\n}\r\n\r\nfunction downloadJar() {\r\n console.log('downloadJar, startujemy pobieranie...');\r\n const version = document.getElementById('versionSelect').value;\r\n if (version && currentServer) {\r\n sendMessage({ type: 'downloadJar', serverName: currentServer, version });\r\n toggleDownloadState(true);\r\n console.log(`Pobieramy wersj臋 ${version} dla ${currentServer}, zajebi艣cie! 馃敟`);\r\n } else {\r\n console.log('Kurwa, brak wersji albo serwera, nic nie pobieram! 馃槨');\r\n }\r\n}\r\n\r\nexport function updateVersionsList(versions, localFiles) {\r\n console.log('updateVersionsList, aktualizujemy list臋 wersji:', versions, localFiles);\r\n const versionSelect = document.getElementById('versionSelect');\r\n if (!versionSelect) {\r\n console.log('Kurwa, brak versionSelect w DOM, nie aktualizuj臋! 馃槨');\r\n return;\r\n }\r\n versionSelect.innerHTML = '<option value=\"\">Wybierz wersj臋</option>';\r\n if (versions && versions.length > 0) {\r\n versions.forEach(v => {\r\n const option = document.createElement('option');\r\n option.value = v.id;\r\n option.textContent = `${v.id}${localFiles.includes(v.id) ? ' (lokalny)' : ''}`;\r\n versionSelect.appendChild(option);\r\n });\r\n console.log(`Wczytano wersje MC: ${versions.map(v => v.id).join(', ')}, zajebi艣cie! 馃槑`);\r\n } else {\r\n console.log('Kurwa, brak wersji do wy艣wietlenia, co艣 zjebane! 馃槨');\r\n }\r\n}\r\n\r\nfunction toggleDownloadState(isDownloading) {\r\n console.log(`toggleDownloadState, stan: ${isDownloading}`);\r\n const versionSelect = document.getElementById('versionSelect');\r\n const downloadBtn = document.getElementById('downloadBtn');\r\n const jarUpload = document.getElementById('jarUpload');\r\n if (versionSelect) versionSelect.disabled = isDownloading;\r\n if (downloadBtn) downloadBtn.disabled = isDownloading;\r\n if (jarUpload) jarUpload.disabled = isDownloading;\r\n if (downloadBtn) downloadBtn.classList.toggle('loading', isDownloading);\r\n}\r\n\r\nexport function handleDownloadProgress(data) {\r\n console.log('handleDownloadProgress, post臋p:', data);\r\n const progressBar = document.getElementById('downloadProgress');\r\n if (!progressBar) {\r\n console.log('Kurwa, brak downloadProgress w DOM! 馃槨');\r\n return;\r\n }\r\n const progressFill = progressBar.querySelector('.progress-fill');\r\n const progressText = progressBar.querySelector('.progress-text');\r\n progressBar.style.display = 'block';\r\n progressFill.style.width = `${data.progress}%`;\r\n progressText.textContent = `${data.progress}% | ${data.downloadedMB}/${data.totalMB} MB | ${data.speed} MB/s`;\r\n console.log(`Post臋p: ${data.progress}%, ${data.downloadedMB}/${data.totalMB} MB, pr臋dko艣膰: ${data.speed} MB/s`);\r\n}\r\n\r\nexport function handleDownloadComplete(data) {\r\n console.log('handleDownloadComplete, pobrano:', data);\r\n const progressBar = document.getElementById('downloadProgress');\r\n if (progressBar) progressBar.style.display = 'none';\r\n toggleDownloadState(false);\r\n document.getElementById('jarUpload').value = '';\r\n sendMessage({ type: 'setJar', serverName: currentServer, jar: data.filename });\r\n fetchVersions();\r\n console.log(`Pobrano ${data.filename}, zajebi艣cie! 馃敟`);\r\n}",
- "Path": "/public/js/java.js",
- "SizeKB": "10,16"
- },
- "/logs/debug_2025-03-16T19-09-40.484Z.log": {
- "Path": "/logs/debug_2025-03-16T19-09-40.484Z.log",
- "SizeKB": "26,86"
- },
- "/logs/server_2025-04-16T15-48-07.953Z.log": {
- "Path": "/logs/server_2025-04-16T15-48-07.953Z.log",
- "SizeKB": "3,12"
- },
- "/public/index.html": {
- "Content": "<!DOCTYPE html>\r\n<html lang=\"pl\">\r\n<head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n <link type=\"image/png\" sizes=\"16x16\" rel=\"icon\" href=\"img/icon_16.png\">\r\n <link type=\"image/png\" sizes=\"32x32\" rel=\"icon\" href=\"img/icon_32.png\">\r\n <link type=\"image/png\" sizes=\"96x96\" rel=\"icon\" href=\"img/icon_96.png\">\r\n <link type=\"image/png\" sizes=\"120x120\" rel=\"icon\" href=\"img/icon_120.png\">\r\n <title>Panel Sterowania MC</title>\r\n <link rel=\"stylesheet\" href=\"css/styles.css\">\r\n <link rel=\"stylesheet\" href=\"css/resourceMonitor.css\">\r\n</head>\r\n<body>\r\n <div class=\"header\">\r\n <h1>Panel Sterowania MC</h1>\r\n </div>\r\n <div class=\"main\">\r\n <div class=\"sidebar\">\r\n <div class=\"add-server\">\r\n <input type=\"text\" id=\"serverName\" placeholder=\"Nazwa serwera\">\r\n <button id=\"addServerBtn\">Dodaj Serwer</button>\r\n </div>\r\n <div class=\"server-list\" id=\"serversList\"></div>\r\n <div class=\"context-menu\" id=\"serverContext\" style=\"display: none;\"></div>\r\n </div>\r\n <div class=\"content\" id=\"serverContent\" style=\"display: none;\">\r\n <div class=\"server-header\">\r\n <div style=\"display: flex; align-items: center;\">\r\n <img id=\"serverIcon\" src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==\" alt=\"Server Icon\">\r\n <h2 id=\"currentServer\"></h2>\r\n </div>\r\n <div class=\"controls\">\r\n <button id=\"startBtn\">W艂膮cz</button>\r\n <button id=\"stopBtn\" disabled>Zatrzymaj</button>\r\n <button id=\"restartBtn\" disabled>Restartuj</button>\r\n <button id=\"killBtn\" disabled>Zabij</button>\r\n <button id=\"deleteBtn\">Usu艅</button>\r\n </div>\r\n </div>\r\n <div class=\"tabs\">\r\n <div class=\"tab active\" data-tab=\"console\">馃摕 Konsola</div>\r\n <div class=\"tab\" data-tab=\"logs\">馃摐 Logi</div>\r\n <div class=\"tab\" data-tab=\"java\">鈽?Java</div>\r\n <div class=\"tab\" data-tab=\"server\">鈿欙笍 Ustawienia serwera</div>\r\n <div class=\"tab\" id=\"modsTab\" data-tab=\"mods\" style=\"display: none;\">馃洜锔?Modyfikacje</div>\r\n <div class=\"tab\" data-tab=\"files\">馃搧 Zarz膮dzaj plikami</div>\r\n <div class=\"tab\" data-tab=\"whitelist\">馃摐 Bia艂a Lista</div>\r\n <div class=\"tab\" data-tab=\"ops\">馃憫 Operatorzy</div>\r\n <div class=\"tab\" data-tab=\"banned\">馃毇 Zbanowani</div>\r\n <div class=\"tab\" data-tab=\"settings\">馃枌锔?Ustawienia</div>\r\n </div>\r\n <div class=\"tab-content active\" id=\"consoleTab\">\r\n <div class=\"console\" id=\"console\"></div>\r\n <div class=\"console-input\">\r\n <input type=\"text\" id=\"consoleInput\" placeholder=\"Wpisz komend臋...\">\r\n <button id=\"sendCommandBtn\">Wy艣lij</button>\r\n <button id=\"clearConsoleBtn\">Wyczy艣膰</button>\r\n </div>\r\n </div>\r\n <div class=\"tab-content\" id=\"logsTab\">\r\n <select class=\"log-select\" id=\"logSelect\">\r\n <option value=\"latest.log\">latest.log</option>\r\n </select>\r\n <div class=\"logs\" id=\"logs\"></div>\r\n </div>\r\n <div class=\"tab-content\" id=\"settingsTab\">\r\n <div class=\"section\">\r\n <h3>Og贸lne</h3>\r\n <div class=\"properties-editor\">\r\n <div>\r\n <label>Nazwa serwera:\r\n <input type=\"text\" id=\"serverNameEdit\">\r\n </label>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"section\">\r\n <h3>Wygl膮d</h3>\r\n <div class=\"properties-editor\">\r\n <div>\r\n <label>Ikona serwera:\r\n <input type=\"file\" accept=\".png\" id=\"iconUpload\">\r\n </label>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"tab-content\" id=\"serverTab\">\r\n <div class=\"properties-editor\" id=\"properties\"></div>\r\n <div class=\"resources\">\r\n <div class=\"gauge-container\" id=\"cpu-gauge\">\r\n <div class=\"gauge\"><div class=\"gauge-needle\"></div></div>\r\n <div class=\"gauge-label\">CPU (%)</div>\r\n <div class=\"gauge-value\"></div>\r\n </div>\r\n <div class=\"gauge-container\" id=\"ram-gauge\">\r\n <div class=\"gauge\"><div class=\"gauge-needle\"></div></div>\r\n <div class=\"gauge-label\">RAM (MB)</div>\r\n <div class=\"gauge-value\"></div>\r\n </div>\r\n <button id=\"backup-btn\">Utw贸rz kopi臋 zapasow膮</button>\r\n </div>\r\n </div>\r\n <div class=\"tab-content\" id=\"bannedTab\">\r\n <h3>Zbanowani Gracze</h3>\r\n <div id=\"bannedPlayers\"></div>\r\n <h3>Zbanowane IP</h3>\r\n <div id=\"bannedIps\"></div>\r\n </div>\r\n <div class=\"tab-content\" id=\"whitelistTab\">\r\n <div id=\"whitelist\"></div>\r\n </div>\r\n <div class=\"tab-content\" id=\"opsTab\">\r\n <div id=\"ops\"></div>\r\n </div>\r\n <div class=\"tab-content\" id=\"modsTab\">\r\n <input type=\"text\" id=\"modSearch\" placeholder=\"Szukaj moda...\">\r\n <input type=\"file\" accept=\".jar\" id=\"modUpload\">\r\n <div class=\"mods-list\" id=\"modsList\"></div>\r\n </div>\r\n <div class=\"tab-content\" id=\"javaTab\">\r\n <div class=\"section\">\r\n <h3>Wersja Javy</h3>\r\n <div class=\"java-panel\" id=\"javaVersionPanel\"></div>\r\n </div>\r\n <div class=\"section\">\r\n <h3>Ustawienia zasob贸w</h3>\r\n <div class=\"java-panel\" id=\"javaResourcesPanel\"></div>\r\n </div>\r\n <div class=\"section\">\r\n <h3>Plik serwera</h3>\r\n <div class=\"java-panel\" id=\"javaJarPanel\">\r\n <input type=\"file\" accept=\".jar\" id=\"jarUpload\">\r\n <span id=\"currentJar\">Nie wybrano pliku.</span>\r\n <div class=\"version-selector\">\r\n <select id=\"versionSelect\">\r\n <option value=\"\">Wybierz wersj臋</option>\r\n </select>\r\n <button id=\"downloadBtn\">馃摜 Pobierz</button>\r\n </div>\r\n <div id=\"downloadProgress\" class=\"download-progress\">\r\n <div class=\"progress-fill\" style=\"width: 0%\"></div>\r\n <div class=\"progress-text\">0% | 0/0 MB | 0 MB/s</div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"tab-content\" id=\"filesTab\">\r\n <div class=\"file-manager\">\r\n <div class=\"files\" id=\"fileList\"></div>\r\n <div class=\"context-menu\" id=\"fileContext\" style=\"display: none;\"></div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"modal\" id=\"entryModal\">\r\n <div class=\"modal-content\">\r\n <h3 id=\"modalTitle\"></h3>\r\n <input type=\"text\" id=\"modalInput\" placeholder=\"Wprowad藕 warto艣膰\">\r\n <div>\r\n <button id=\"submitModalBtn\">Dodaj</button>\r\n <button id=\"closeModalBtn\">Anuluj</button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Podpinanie modu艂贸w JS -->\r\n <script src=\"js/main.js\" type=\"module\"></script>\r\n <script src=\"js/websocket.js\" type=\"module\"></script>\r\n <script src=\"js/ui.js\" type=\"module\"></script>\r\n <script src=\"js/server.js\" type=\"module\"></script>\r\n <script src=\"js/files.js\" type=\"module\"></script>\r\n <script src=\"js/mods.js\" type=\"module\"></script>\r\n <script src=\"js/settings.js\" type=\"module\"></script>\r\n <script src=\"js/java.js\" type=\"module\"></script>\r\n <script src=\"js/resourceMonitor.js\" type=\"module\"></script>\r\n <script src=\"js/backup.js\" type=\"module\"></script>\r\n</body>\r\n</html>",
- "Path": "/public/index.html",
- "SizeKB": "8,59"
- },
- "/logs/minecraft_2025-04-16T15-30-48.625Z.log": {
- "Path": "/logs/minecraft_2025-04-16T15-30-48.625Z.log",
- "SizeKB": "1,70"
- },
- "/public/img/icon_120.png": {
- "Path": "/public/img/icon_120.png",
- "SizeKB": "3,73"
- },
- "/logs/app_2025-03-16T15-17-44.816Z.log": {
- "Path": "/logs/app_2025-03-16T15-17-44.816Z.log",
- "SizeKB": "5,44"
- },
- "/logs/server_2025-04-16T15-38-13.014Z.log": {
- "Path": "/logs/server_2025-04-16T15-38-13.014Z.log",
- "SizeKB": "3,59"
- },
- "/logs/debug.log": {
- "Path": "/logs/debug.log",
- "SizeKB": "11,65"
- },
- "/logs/minecraft_2025-03-16T19-09-40.484Z.log": {
- "Path": "/logs/minecraft_2025-03-16T19-09-40.484Z.log",
- "SizeKB": "0,44"
- },
- "/public/js/main.js": {
- "Content": "import { initWebSocket } from './websocket.js';\r\nimport { initUI } from './ui.js';\r\nimport { initServers } from './server.js';\r\nimport { initFiles } from './files.js';\r\nimport { initMods } from './mods.js';\r\nimport { initSettings } from './settings.js';\r\nimport { initJava } from './java.js';\r\nimport { ResourceMonitor } from './resourceMonitor.js';\r\nimport { BackupHandler } from './backup.js';\r\n\r\ndocument.addEventListener('DOMContentLoaded', () => {\r\n console.log('Kurwa, ziom, appka startuje! 馃槀');\r\n initWebSocket();\r\n initServers();\r\n initUI();\r\n initFiles();\r\n initMods();\r\n initSettings();\r\n initJava();\r\n new ResourceMonitor();\r\n new BackupHandler();\r\n});",
- "Path": "/public/js/main.js",
- "SizeKB": "0,68"
- },
- "/logs/app_2025-03-16T15-11-15.055Z.log": {
- "Path": "/logs/app_2025-03-16T15-11-15.055Z.log",
- "SizeKB": "0,58"
- },
- "/logs/server_2025-03-22T17-46-05.557Z.log": {
- "Path": "/logs/server_2025-03-22T17-46-05.557Z.log",
- "SizeKB": "4,94"
- },
- "/logs/app_2025-03-22T17-46-05.557Z.log": {
- "Path": "/logs/app_2025-03-22T17-46-05.557Z.log",
- "SizeKB": "0,10"
- },
- "/logs/debug_2025-04-16T15-30-48.625Z.log": {
- "Path": "/logs/debug_2025-04-16T15-30-48.625Z.log",
- "SizeKB": "20,53"
- },
- "/server/utils/helpers.js": {
- "Content": "const path = require('path');\r\nconst { javaVersions } = require('../controllers/javaManager');\r\n\r\nfunction createDefaultInstance(name) {\r\n // Sprawdzamy, czy javaVersions istnieje i ma co艣 w 艣rodku, inaczej bierzemy konkretn膮 wersj臋\r\n const defaultJava = javaVersions && javaVersions.length > 0 ? javaVersions[0] : \r\n { version: 'jdk-21', path: 'C:\\\\Users\\\\Admin\\\\Desktop\\\\minecraft-server-manager\\\\server\\\\javas\\\\jdk-21\\\\bin\\\\java.exe' };\r\n\r\n return {\r\n name,\r\n dir: path.join(__dirname, '../servers', name),\r\n jar: null,\r\n java: defaultJava.version,\r\n javaPath: defaultJava.path,\r\n ram: 4,\r\n version: null,\r\n process: null,\r\n running: false,\r\n properties: {\r\n 'motd': 'Serwer MC',\r\n 'difficulty': 'normal',\r\n 'pvp': 'false',\r\n 'max-players': '20',\r\n 'online-mode': 'true'\r\n },\r\n files: {\r\n 'banned-ips.json': '[]',\r\n 'banned-players.json': '[]',\r\n 'ops.json': '[]',\r\n 'whitelist.json': '[]'\r\n },\r\n hasMods: false,\r\n mods: []\r\n };\r\n}\r\n\r\nmodule.exports = { createDefaultInstance };",
- "Path": "/server/utils/helpers.js",
- "SizeKB": "1,18"
- },
- "/_TEMP/server-icon.png": {
- "Path": "/_TEMP/server-icon.png",
- "SizeKB": "3,47"
- },
- "/logs/app_2025-03-16T15-08-18.725Z.log": {
- "Path": "/logs/app_2025-03-16T15-08-18.725Z.log",
- "SizeKB": "0,72"
- },
- "/.vscode/launch.json": {
- "Content": "{\r\n \"version\": \"0.2.0\",\r\n \"configurations\": [\r\n {\r\n \"type\": \"node\",\r\n \"request\": \"launch\",\r\n \"name\": \"Uruchom Minecraft Server Manager\",\r\n \"program\": \"${workspaceFolder}/server/server.js\",\r\n \"cwd\": \"${workspaceFolder}\",\r\n \"runtimeExecutable\": \"node\",\r\n \"runtimeArgs\": [\"--inspect\"],\r\n \"console\": \"integratedTerminal\",\r\n \"skipFiles\": [\"<node_internals>/**\"],\r\n \"env\": {\r\n \"NODE_ENV\": \"development\"\r\n }\r\n }\r\n ]\r\n}",
- "Path": "/.vscode/launch.json",
- "SizeKB": "0,47"
- },
- "/_create-empty-tree.bat": {
- "Content": "# Tworzenie katalog贸w\r\n$folders = @(\r\n \"public\", \"public\\css\", \"public\\js\", \"public\\img\",\r\n \"server\", \"server\\controllers\", \"server\\utils\", \"server\\servers\",\r\n \"server\\javas\", \"logs\"\r\n)\r\n\r\nforeach ($folder in $folders) {\r\n New-Item -Path $folder -ItemType Directory -Force | Out-Null\r\n}\r\n\r\n# Tworzenie pustych plik贸w\r\n$files = @(\r\n \"public\\css\\styles.css\",\r\n \"public\\css\\dark-theme.css\",\r\n \"public\\css\\light-theme.css\",\r\n \r\n \"public\\js\\main.js\",\r\n \"public\\js\\websocket.js\",\r\n \"public\\js\\ui.js\",\r\n \"public\\js\\server.js\",\r\n \"public\\js\\files.js\",\r\n \"public\\js\\mods.js\",\r\n \"public\\js\\settings.js\",\r\n \"public\\js\\java.js\",\r\n \r\n \"public\\index.html\",\r\n \r\n \"server\\controllers\\serverManager.js\",\r\n \"server\\controllers\\fileManager.js\",\r\n \"server\\controllers\\javaManager.js\",\r\n \"server\\controllers\\wsHandler.js\",\r\n \r\n \"server\\utils\\logger.js\",\r\n \"server\\utils\\configLoader.js\",\r\n \"server\\utils\\helpers.js\",\r\n \r\n \"server\\server.js\",\r\n \"server\\config.json\",\r\n \r\n \"logs\\app.log\",\r\n \"logs\\error.log\",\r\n \r\n \".gitignore\",\r\n \"start.sh\",\r\n \"start.bat\",\r\n \"README.md\"\r\n)\r\n\r\nforeach ($file in $files) {\r\n New-Item -Path $file -ItemType File -Force | Out-Null\r\n}\r\n\r\nWrite-Host \"鉁?Struktura projektu zosta艂a utworzona!\" -ForegroundColor Green\r\n",
- "Path": "/_create-empty-tree.bat",
- "SizeKB": "1,31"
- },
- "/logs/server_2025-04-16T15-40-49.225Z.log": {
- "Path": "/logs/server_2025-04-16T15-40-49.225Z.log",
- "SizeKB": "2,79"
- },
- "/logs/minecraft_2025-04-16T15-33-05.987Z.log": {
- "Path": "/logs/minecraft_2025-04-16T15-33-05.987Z.log",
- "SizeKB": "0,16"
- },
- "/logs/debug_2025-03-16T15-17-44.816Z.log": {
- "Path": "/logs/debug_2025-03-16T15-17-44.816Z.log",
- "SizeKB": "14,47"
- },
- "/public/js/server.js": {
- "Content": "import { sendMessage, sendDebouncedMessage, servers, setCurrentServer, setUpdateCallbacks, currentServer, consoleLines, MAX_LINES } from './websocket.js';\r\nimport { updateMods } from './mods.js';\r\nimport { updateJava } from './java.js'; // Importujemy updateJava\r\n\r\nexport function updateServersList() {\r\n const list = document.getElementById('serversList');\r\n if (!list) {\r\n console.log('Kurwa, nie ma serversList w DOM! 馃槨 Sprawd藕 HTML!');\r\n return;\r\n }\r\n list.innerHTML = '';\r\n Object.keys(servers).forEach(name => {\r\n const div = document.createElement('div');\r\n div.className = `server-item ${currentServer === name ? 'active' : ''}`;\r\n const dot = document.createElement('span');\r\n dot.className = `status-dot ${servers[name].running ? 'green' : servers[name].crashed ? 'yellow' : 'red'}`;\r\n div.appendChild(dot);\r\n const versionText = servers[name].mcVersion ? ` (MC ${servers[name].mcVersion})` : '';\r\n div.appendChild(document.createTextNode(`${name}${versionText}`));\r\n div.addEventListener('click', () => selectServer(name));\r\n div.addEventListener('contextmenu', (e) => showServerContext(e));\r\n list.appendChild(div);\r\n });\r\n console.log('Lista serwer贸w zaktualizowana, kurwa git! 馃槑', Object.keys(servers));\r\n}\r\n\r\nexport function updateServerView(name) {\r\n if (!servers[name]) {\r\n console.log(`Serwer ${name} nie istnieje, kurwa! 馃槨`);\r\n return;\r\n }\r\n\r\n // Aktualizacja podstawowych informacji o serwerze\r\n document.getElementById('currentServer').textContent = servers[name].mcVersion ? `${name} (MC ${servers[name].mcVersion})` : name;\r\n document.getElementById('serverNameEdit').value = name;\r\n const isRunning = servers[name].running;\r\n document.getElementById('startBtn').disabled = isRunning;\r\n document.getElementById('stopBtn').disabled = !isRunning;\r\n document.getElementById('restartBtn').disabled = !isRunning;\r\n document.getElementById('killBtn').disabled = !isRunning;\r\n document.getElementById('deleteBtn').disabled = isRunning;\r\n document.getElementById('serverNameEdit').disabled = isRunning;\r\n document.getElementById('iconUpload').disabled = isRunning;\r\n document.getElementById('modsTab').style.display = servers[name].hasMods ? 'block' : 'none';\r\n\r\n // Aktualizacja sekcji Javy i RAM-u\r\n updateJava(name);\r\n console.log(`Zaktualizowano sekcj臋 Javy dla ${name}, zajebi艣cie! 馃敟`);\r\n\r\n // Aktualizacja innych sekcji\r\n updateProperties(servers[name].properties);\r\n updatePlayersManagement('bannedPlayers', 'banned-players.json', ['Nick', 'Pow贸d', 'Usu艅'], 'name');\r\n updatePlayersManagement('bannedIps', 'banned-ips.json', ['IP', 'Pow贸d', 'Usu艅'], 'ip');\r\n updatePlayersManagement('whitelist', 'whitelist.json', ['Nick', 'Usu艅'], 'name');\r\n updatePlayersManagement('ops', 'ops.json', ['Nick', 'Poziom', 'Usu艅'], 'name');\r\n updateMods(name);\r\n updateConsole(name);\r\n}\r\n\r\nexport function initServers() {\r\n document.getElementById('addServerBtn').addEventListener('click', addServer);\r\n document.getElementById('startBtn').addEventListener('click', startServer);\r\n document.getElementById('stopBtn').addEventListener('click', stopServer);\r\n document.getElementById('restartBtn').addEventListener('click', restartServer);\r\n document.getElementById('killBtn').addEventListener('click', killServer);\r\n document.getElementById('deleteBtn').addEventListener('click', deleteServer);\r\n document.getElementById('sendCommandBtn').addEventListener('click', sendCommand);\r\n document.getElementById('clearConsoleBtn').addEventListener('click', clearConsole);\r\n document.getElementById('consoleInput').addEventListener('keydown', (e) => {\r\n if (e.key === 'Enter') sendCommand();\r\n });\r\n\r\n setUpdateCallbacks({\r\n updateServersList,\r\n updateServerView,\r\n appendConsole: (serverName, output) => {\r\n if (!consoleLines.has(serverName)) consoleLines.set(serverName, []);\r\n const lines = consoleLines.get(serverName);\r\n lines.push(output);\r\n if (lines.length > MAX_LINES) lines.shift();\r\n if (serverName === currentServer) updateConsole(serverName);\r\n },\r\n detectServerVersion: (serverName, output) => {\r\n const match = output.match(/Starting minecraft server version (.+)/);\r\n if (match && currentServer === serverName) {\r\n const mcVersion = match[1];\r\n sendMessage({ type: 'setMcVersion', serverName, version: mcVersion });\r\n console.log(`Wykryto wersj臋 MC ${mcVersion} dla ${serverName}, kurwa spoko! 馃槀`);\r\n }\r\n }\r\n });\r\n\r\n // Czekamy na DOM i odpalamy aktualizacj臋\r\n document.addEventListener('DOMContentLoaded', () => {\r\n console.log('DOM gotowy, sprawdzam serwery!', servers);\r\n if (Object.keys(servers).length > 0) {\r\n updateServersList();\r\n console.log('Serwery by艂y przed DOM-em, aktualizuj臋 list臋! 馃敟');\r\n } else {\r\n console.log('Kurwa, serwery jeszcze nie przysz艂y, czekam...');\r\n }\r\n }, { once: true });\r\n}\r\n\r\nfunction addServer() {\r\n const name = document.getElementById('serverName').value;\r\n if (name) {\r\n sendMessage({ type: 'addServer', name });\r\n document.getElementById('serverName').value = '';\r\n }\r\n}\r\n\r\nfunction selectServer(name) {\r\n setCurrentServer(name);\r\n updateServersList();\r\n updateServerView(name);\r\n document.getElementById('serverContent').style.display = 'block';\r\n if (document.querySelector('.tab.active').dataset.tab === 'files') {\r\n sendMessage({ type: 'getFiles', serverName: name, path: '' });\r\n }\r\n sendMessage({ type: 'getIcon', serverName: name });\r\n loadConsoleFromLog(name);\r\n}\r\n\r\nfunction startServer() {\r\n if (currentServer) sendMessage({ type: 'startServer', serverName: currentServer });\r\n console.log(`Startuj臋 ${currentServer}, niech si臋 dzieje! 馃敟`);\r\n}\r\n\r\nfunction stopServer() {\r\n if (currentServer) sendMessage({ type: 'stopServer', serverName: currentServer });\r\n console.log(`Zatrzymuj臋 ${currentServer}, chill! 馃槢`);\r\n}\r\n\r\nfunction restartServer() {\r\n if (currentServer) sendMessage({ type: 'restartServer', serverName: currentServer });\r\n console.log(`Restartuj臋 ${currentServer}, dawaj na nowo! 馃挭`);\r\n}\r\n\r\nfunction killServer() {\r\n if (currentServer) sendMessage({ type: 'killServer', serverName: currentServer });\r\n console.log(`Zabijam ${currentServer}, bez lito艣ci! 馃槇`);\r\n}\r\n\r\nfunction deleteServer() {\r\n if (currentServer && !servers[currentServer].running) {\r\n sendMessage({ type: 'deleteServer', serverName: currentServer });\r\n setCurrentServer(null);\r\n document.getElementById('serverContent').style.display = 'none';\r\n }\r\n}\r\n\r\nfunction sendCommand() {\r\n const input = document.getElementById('consoleInput');\r\n const command = input.value.trim();\r\n if (command && currentServer) {\r\n sendMessage({ type: 'sendCommand', serverName: currentServer, command });\r\n input.value = '';\r\n console.log(`Wys艂a艂em komend臋 \"${command}\" do ${currentServer}, zajebi艣cie! 馃憤`);\r\n }\r\n}\r\n\r\nfunction clearConsole() {\r\n if (currentServer) {\r\n consoleLines.set(currentServer, []);\r\n updateConsole(currentServer);\r\n }\r\n}\r\n\r\nfunction loadConsoleFromLog(serverName) {\r\n const lines = consoleLines.get(serverName) || [];\r\n if (lines.length === 0) consoleLines.set(serverName, []);\r\n updateConsole(serverName);\r\n}\r\n\r\nfunction updateConsole(serverName) {\r\n const consoleDiv = document.getElementById('console');\r\n const lines = consoleLines.get(serverName) || [];\r\n consoleDiv.textContent = lines.join('\\n');\r\n consoleDiv.scrollTop = consoleDiv.scrollHeight;\r\n}\r\n\r\nexport function showServerContext(event) {\r\n event.preventDefault();\r\n const target = event.target.closest('.server-item');\r\n if (!target) return;\r\n const name = target.textContent.split(' (MC')[0].trim();\r\n const isRunning = servers[name].running;\r\n const menu = document.getElementById('serverContext');\r\n menu.innerHTML = '';\r\n\r\n if (!isRunning) {\r\n const start = document.createElement('div');\r\n start.textContent = '馃煝 W艂膮cz';\r\n start.addEventListener('click', startServer);\r\n menu.appendChild(start);\r\n }\r\n if (isRunning) {\r\n const stop = document.createElement('div');\r\n stop.textContent = '馃敶 Zatrzymaj';\r\n stop.addEventListener('click', stopServer);\r\n menu.appendChild(stop);\r\n\r\n const restart = document.createElement('div');\r\n restart.textContent = '馃攧 Restartuj';\r\n restart.addEventListener('click', restartServer);\r\n menu.appendChild(restart);\r\n\r\n const kill = document.createElement('div');\r\n kill.textContent = '馃拃 Zabij';\r\n kill.addEventListener('click', killServer);\r\n menu.appendChild(kill);\r\n }\r\n if (!isRunning) {\r\n const del = document.createElement('div');\r\n del.textContent = '馃棏锔?Usu艅';\r\n del.addEventListener('click', deleteServer);\r\n menu.appendChild(del);\r\n }\r\n\r\n menu.style.left = `${event.pageX}px`;\r\n menu.style.top = `${event.pageY}px`;\r\n menu.style.display = 'block';\r\n document.addEventListener('click', () => menu.style.display = 'none', { once: true });\r\n}\r\n\r\nlet updateProperties = () => {};\r\nlet updatePlayersManagement = () => {};\r\nexport function setServerCallbacks({ properties, players, mods }) {\r\n updateProperties = properties || updateProperties;\r\n updatePlayersManagement = players || updatePlayersManagement;\r\n if (mods) updateMods = mods;\r\n}",
- "Path": "/public/js/server.js",
- "SizeKB": "9,59"
- },
- "/_TEMP/orignal.7z": {
- "Path": "/_TEMP/orignal.7z",
- "SizeKB": "2聽607聽017,96"
- },
- "/logs/debug_2025-03-16T14-50-54.242Z.log": {
- "Path": "/logs/debug_2025-03-16T14-50-54.242Z.log",
- "SizeKB": "12,23"
- },
- "/logs/debug_2025-03-16T15-11-15.055Z.log": {
- "Path": "/logs/debug_2025-03-16T15-11-15.055Z.log",
- "SizeKB": "9,97"
- },
- "/logs/minecraft_2025-03-16T15-17-44.816Z.log": {
- "Path": "/logs/minecraft_2025-03-16T15-17-44.816Z.log",
- "SizeKB": "0,92"
- },
- "/logs/minecraft_2025-03-16T15-00-13.680Z.log": {
- "Path": "/logs/minecraft_2025-03-16T15-00-13.680Z.log",
- "SizeKB": "0,72"
- },
- "/public/js/mods.js": {
- "Content": "import { sendMessage, servers, currentServer } from './websocket.js';\r\n\r\nexport function initMods() {\r\n document.getElementById('modUpload').addEventListener('change', uploadMod);\r\n document.getElementById('modSearch').addEventListener('input', (e) => filterMods(e.target.value));\r\n}\r\n\r\nfunction updateMods(serverName) {\r\n const list = document.getElementById('modsList');\r\n list.innerHTML = '';\r\n const isRunning = servers[serverName].running;\r\n const mods = servers[serverName].mods || [];\r\n mods.forEach(mod => {\r\n const div = document.createElement('div');\r\n div.textContent = mod;\r\n const btns = document.createElement('span');\r\n btns.innerHTML = `\r\n <button onclick=\"toggleMod('${mod}', ${!mod.endsWith('.disabled')})\" ${isRunning ? 'disabled' : ''}>${mod.endsWith('.disabled') ? 'W艂膮cz' : 'Wy艂膮cz'}</button>\r\n <button onclick=\"deleteMod('${mod}')\" ${isRunning ? 'disabled' : ''}>Usu艅</button>\r\n `;\r\n div.appendChild(btns);\r\n list.appendChild(div);\r\n });\r\n document.getElementById('modUpload').disabled = isRunning;\r\n}\r\n\r\nfunction filterMods(query) {\r\n const list = document.getElementById('modsList');\r\n Array.from(list.children).forEach(div => {\r\n div.style.display = div.textContent.toLowerCase().includes(query.toLowerCase()) ? 'flex' : 'none';\r\n });\r\n}\r\n\r\nfunction toggleMod(mod, disable) {\r\n if (servers[currentServer].running) return;\r\n sendMessage({ type: disable ? 'disableMod' : 'enableMod', serverName: currentServer, mod });\r\n}\r\n\r\nfunction uploadMod() {\r\n const file = document.getElementById('modUpload').files[0];\r\n if (file && currentServer && !servers[currentServer].running) {\r\n const reader = new FileReader();\r\n reader.onload = () => sendMessage({ type: 'uploadMod', serverName: currentServer, data: reader.result, filename: file.name });\r\n reader.readAsDataURL(file);\r\n }\r\n}\r\n\r\nfunction deleteMod(mod) {\r\n if (currentServer && !servers[currentServer].running) {\r\n sendMessage({ type: 'deleteMod', serverName: currentServer, mod });\r\n }\r\n}\r\n\r\nexport { updateMods };",
- "Path": "/public/js/mods.js",
- "SizeKB": "2,11"
- },
- "/public/js/websocket.js": {
- "Content": "import { updateServersList, updateServerView } from './server.js';\r\nimport { updateLogs } from './ui.js';\r\nimport { updateJava, updateJavaVersions, handleDownloadProgress, handleDownloadComplete } from './java.js';\r\n\r\nexport let ws;\r\nexport const servers = {};\r\nexport let currentServer = null;\r\nexport const consoleLines = new Map();\r\nexport const javaVersions = [];\r\nexport const MAX_LINES = 1000;\r\n\r\nlet reconnectAttempts = 0;\r\nconst maxReconnectAttempts = 5;\r\nlet isInitialized = false;\r\n\r\nconst callbacks = {\r\n updateServersList: () => console.log('Kurwa, updateServersList nie podpi臋te jeszcze! 馃槨'),\r\n updateServerView: () => console.log('Kurwa, updateServerView nie podpi臋te jeszcze! 馃槨'),\r\n appendConsole: () => {},\r\n detectServerVersion: () => {},\r\n updateFileList: () => {},\r\n updateVersionsList: () => {},\r\n handleDownloadProgress: () => {},\r\n handleDownloadComplete: () => {}\r\n};\r\n\r\nexport function setUpdateCallbacks({ updateServersList, updateServerView, appendConsole, detectServerVersion, updateFileList, updateVersionsList, handleDownloadProgress, handleDownloadComplete }) {\r\n if (updateServersList) callbacks.updateServersList = updateServersList;\r\n if (updateServerView) callbacks.updateServerView = updateServerView;\r\n if (appendConsole) callbacks.appendConsole = appendConsole;\r\n if (detectServerVersion) callbacks.detectServerVersion = detectServerVersion;\r\n if (updateFileList) callbacks.updateFileList = updateFileList;\r\n if (updateVersionsList) callbacks.updateVersionsList = updateVersionsList;\r\n if (handleDownloadProgress) callbacks.handleDownloadProgress = handleDownloadProgress;\r\n if (handleDownloadComplete) callbacks.handleDownloadComplete = handleDownloadComplete;\r\n}\r\n\r\nexport function setCurrentServer(name) {\r\n currentServer = name;\r\n console.log(`Prze艂膮czam na serwer: ${currentServer}, kurwa! 馃槑`);\r\n if (currentServer && servers[currentServer]) {\r\n console.log(`Dane serwera ${currentServer}:`, servers[currentServer]);\r\n callbacks.updateServerView(currentServer);\r\n } else {\r\n console.log(`Serwer ${currentServer} nie istnieje, kurwa ma膰! 馃槨`);\r\n }\r\n}\r\n\r\nfunction connect() {\r\n ws = new WebSocket('ws://192.168.0.197:8080');\r\n\r\n ws.onopen = () => {\r\n console.log('WebSocket pod艂膮czony, zajebi艣cie! 馃敟');\r\n reconnectAttempts = 0;\r\n if (!isInitialized) {\r\n setTimeout(() => {\r\n sendMessage({ type: 'getServers' });\r\n console.log('Wys艂ano getServers, kurwa czekamy na odpowied藕! 馃槑');\r\n isInitialized = true;\r\n }, 100);\r\n } else {\r\n // Po reconnectcie od艣wie偶amy serwery\r\n sendMessage({ type: 'getServers' });\r\n console.log('Reconnect, wysy艂am getServers ponownie, kurwa! 馃槢');\r\n }\r\n };\r\n\r\n ws.onmessage = (event) => {\r\n const data = JSON.parse(event.data);\r\n console.log('WebSocket dane:', data);\r\n switch (data.type) {\r\n case 'servers':\r\n console.log('Odebrano serwery, kurwa lecimy!', data.servers);\r\n Object.assign(servers, data.servers);\r\n console.log('Serwery z backendu:', servers);\r\n callbacks.updateServersList();\r\n if (currentServer) setCurrentServer(currentServer);\r\n break;\r\n case 'console':\r\n console.log(`Konsola dla ${data.serverName}: ${data.output}`);\r\n callbacks.appendConsole(data.serverName, data.output);\r\n callbacks.detectServerVersion(data.serverName, data.output);\r\n break;\r\n case 'javaVersions':\r\n console.log('Odebrano wersje Javy:', data.versions);\r\n javaVersions.length = 0;\r\n javaVersions.push(...data.versions);\r\n updateJavaVersions();\r\n break;\r\n case 'fileList':\r\n console.log(`Lista plik贸w dla ${data.path}:`, data.files);\r\n callbacks.updateFileList(data.path, data.files);\r\n break;\r\n case 'icon':\r\n console.log(`Ikona dla ${data.serverName} odebrana`);\r\n document.getElementById('serverIcon').src = data.data;\r\n break;\r\n case 'logContent':\r\n console.log('Odebrano logi:', data.logContent);\r\n updateLogs(data.logContent);\r\n break;\r\n case 'resourceUpdate':\r\n console.log('Aktualizacja zasob贸w:', data);\r\n break;\r\n case 'versionsList':\r\n console.log(`Odebrano wersje MC dla ${data.serverName}:`, data.versions, 'Lokalne:', data.localFiles);\r\n callbacks.updateVersionsList(data.versions, data.localFiles);\r\n console.log('Przekazano wersje do updateVersionsList, powinno si臋 za艂adowa膰! 馃槑');\r\n break;\r\n case 'downloadProgress':\r\n console.log('Post臋p pobierania:', data);\r\n callbacks.handleDownloadProgress(data);\r\n break;\r\n case 'downloadComplete':\r\n console.log('Pobieranie zako艅czone:', data);\r\n callbacks.handleDownloadComplete(data);\r\n break;\r\n default:\r\n console.log('Nieznany typ wiadomo艣ci, kurwa co to?', data);\r\n }\r\n };\r\n\r\n ws.onclose = () => {\r\n console.log('WebSocket roz艂膮czony, kurwa ma膰! 馃槩');\r\n if (reconnectAttempts < maxReconnectAttempts) {\r\n reconnectAttempts++;\r\n setTimeout(connect, 1000 * reconnectAttempts);\r\n } else {\r\n console.log('Za du偶o pr贸b, pierdol臋 to! 馃槨');\r\n }\r\n };\r\n\r\n ws.onerror = (err) => {\r\n console.log('WebSocket error, co za chujnia! 馃槨', err);\r\n };\r\n}\r\n\r\nexport function sendMessage(message) {\r\n if (ws && ws.readyState === WebSocket.OPEN) {\r\n ws.send(JSON.stringify(message));\r\n console.log('Wys艂ano wiadomo艣膰:', message);\r\n } else {\r\n console.log('WebSocket niegotowy, kurwa czekaj!', message);\r\n }\r\n}\r\n\r\nconst debounce = (func, wait) => {\r\n let timeout;\r\n return (...args) => {\r\n clearTimeout(timeout);\r\n timeout = setTimeout(() => func(...args), wait);\r\n };\r\n};\r\n\r\nexport const sendDebouncedMessage = debounce((message) => {\r\n if (ws && ws.readyState === WebSocket.OPEN) {\r\n ws.send(JSON.stringify(message));\r\n } else {\r\n console.log('WebSocket niegotowy, kurwa ma膰! 馃槨');\r\n }\r\n}, 500);\r\n\r\nexport function initWebSocket() {\r\n connect();\r\n}\r\n\r\nif (!isInitialized) {\r\n initWebSocket();\r\n}",
- "Path": "/public/js/websocket.js",
- "SizeKB": "6,59"
- },
- "/TODO.MD": {
- "Content": "馃摝 minecraft-server-manager\r\n鈹傗攢鈹€ 馃搨 public # Frontend, pliki statyczne\r\n鈹? 鈹溾攢鈹€ 馃搨 css # Pliki styl贸w\r\n鈹? 鈹? 鈹溾攢鈹€ styles.css # G艂贸wne style interfejsu\r\n鈹? 鈹? 鈹溾攢鈹€ dark-theme.css # Styl ciemny (opcjonalnie)\r\n鈹? 鈹? 鈹溾攢鈹€ light-theme.css # Styl jasny (opcjonalnie)\r\n鈹? 鈹俓r\n鈹? 鈹溾攢鈹€ 馃搨 js # Kod frontendowy (podzielony na modu艂y)\r\n鈹? 鈹? 鈹溾攢鈹€ main.js # G艂贸wna logika aplikacji\r\n鈹? 鈹? 鈹溾攢鈹€ websocket.js # Obs艂uga WebSocket贸w\r\n鈹? 鈹? 鈹溾攢鈹€ ui.js # Logika interfejsu u偶ytkownika\r\n鈹? 鈹? 鈹溾攢鈹€ server.js # Zarz膮dzanie serwerami (frontend)\r\n鈹? 鈹? 鈹溾攢鈹€ files.js # Obs艂uga plik贸w serwera\r\n鈹? 鈹? 鈹溾攢鈹€ mods.js # Obs艂uga mod贸w\r\n鈹? 鈹? 鈹溾攢鈹€ settings.js # Edycja ustawie艅 serwera\r\n鈹? 鈹? 鈹溾攢鈹€ java.js # Obs艂uga wersji Java\r\n鈹? 鈹俓r\n鈹? 鈹溾攢鈹€ 馃搨 img # Ikony, grafiki\r\n鈹? 鈹? 鈹溾攢鈹€ icon_16.png # Favicon 16px\r\n鈹? 鈹? 鈹溾攢鈹€ icon_32.png # Favicon 32px\r\n鈹? 鈹? 鈹溾攢鈹€ icon_96.png # Favicon 96px\r\n鈹? 鈹? 鈹溾攢鈹€ icon_120.png # Favicon 120px\r\n鈹? 鈹俓r\n鈹? 鈹溾攢鈹€ index.html # G艂贸wny plik frontendowy\r\n鈹俓r\n鈹傗攢鈹€ 馃搨 server # Backend, logika serwera\r\n鈹? 鈹溾攢鈹€ 馃搨 controllers # Modu艂y obs艂uguj膮ce r贸偶ne funkcje\r\n鈹? 鈹? 鈹溾攢鈹€ serverManager.js # Obs艂uga zarz膮dzania serwerami MC\r\n鈹? 鈹? 鈹溾攢鈹€ fileManager.js # Operacje na plikach\r\n鈹? 鈹? 鈹溾攢鈹€ javaManager.js # Obs艂uga wersji Java\r\n鈹? 鈹? 鈹溾攢鈹€ wsHandler.js # Obs艂uga WebSocket贸w\r\n鈹? 鈹俓r\n鈹? 鈹溾攢鈹€ 馃搨 utils # Funkcje pomocnicze\r\n鈹? 鈹? 鈹溾攢鈹€ logger.js # System logowania (np. Winston)\r\n鈹? 鈹? 鈹溾攢鈹€ configLoader.js # 艁adowanie pliku konfiguracyjnego\r\n鈹? 鈹? 鈹溾攢鈹€ helpers.js # Pomocnicze funkcje\r\n鈹? 鈹俓r\n鈹? 鈹溾攢鈹€ 馃搨 servers # Folder na instancje serwer贸w MC\r\n鈹? 鈹? 鈹溾攢鈹€ 馃搨 serwer1 # Przyk艂adowa instancja serwera\r\n鈹? 鈹? 鈹? 鈹溾攢鈹€ server.jar # Plik JAR serwera\r\n鈹? 鈹? 鈹? 鈹溾攢鈹€ server.properties # Konfiguracja serwera\r\n鈹? 鈹? 鈹? 鈹溾攢鈹€ eula.txt # Licencja Minecraft EULA\r\n鈹? 鈹? 鈹? 鈹溾攢鈹€ logs # Logi serwera\r\n鈹? 鈹? 鈹? 鈹溾攢鈹€ mods # Folder na mody\r\n鈹? 鈹? 鈹? 鈹溾攢鈹€ world # Pliki 艣wiata\r\n鈹? 鈹俓r\n鈹? 鈹溾攢鈹€ 馃搨 javas # Folder z wersjami Javy\r\n鈹? 鈹? 鈹溾攢鈹€ java-17 # Przyk艂adowa wersja Javy\r\n鈹? 鈹? 鈹溾攢鈹€ java-20 # Przyk艂adowa wersja Javy\r\n鈹? 鈹俓r\n鈹? 鈹溾攢鈹€ server.js # G艂贸wny plik backendu (Express + WebSocket)\r\n鈹? 鈹溾攢鈹€ config.json # Plik konfiguracyjny aplikacji\r\n鈹? 鈹溾攢鈹€ package.json # Plik zale偶no艣ci Node.js\r\n鈹? 鈹溾攢鈹€ README.md # Dokumentacja projektu\r\n鈹俓r\n鈹傗攢鈹€ 馃搨 logs # Folder na logi aplikacji\r\n鈹? 鈹溾攢鈹€ app.log # Logi dzia艂ania aplikacji\r\n鈹? 鈹溾攢鈹€ error.log # Logi b艂臋d贸w\r\n鈹俓r\n鈹傗攢鈹€ .gitignore # Ignorowane pliki dla Gita\r\n鈹傗攢鈹€ start.sh # Skrypt startowy dla Linux/macOS\r\n鈹傗攢鈹€ start.bat # Skrypt startowy dla Windows\r\n\r\n\r\n\r\n\r\n1. Og贸lny Zarys Projektu\r\nCel projektu:\r\nStworzy膰 wszechstronny, responsywny i intuicyjny panel do zarz膮dzania serwerami Minecraft, kt贸ry 艂膮czy w sobie funkcje monitorowania stanu serwera, sterowania jego dzia艂aniem, edycji konfiguracji (server.properties, pliki JSON), zarz膮dzania 艣wiatami, graczami, plikami, modami, ustawieniami Javy, a tak偶e wy艣wietlania log贸w i konsoli.\r\nDlaczego to jest potrzebne?\r\n\r\nUmo偶liwia administratorom szybki dost臋p do kluczowych funkcji serwera w jednym miejscu.\r\nPozwala na 艂atw膮 edycj臋 konfiguracji bez konieczno艣ci r臋cznego modyfikowania plik贸w.\r\nU艂atwia monitorowanie stanu serwera, co jest niezb臋dne przy du偶ej liczbie graczy i cz臋stych zmianach.\r\nIntegruje funkcje backupu i zarz膮dzania plikami, co zwi臋ksza bezpiecze艅stwo i stabilno艣膰 dzia艂ania serwera.\r\n2. Struktura Interfejsu\r\nA. Nag艂贸wek z Zak艂adkami\r\nElementy: Pasek u g贸ry z dynamicznie prze艂膮czanymi zak艂adkami (Dashboard, Sterowanie, Konfiguracja, 艢wiaty, Konsola, Pliki, Gracze, Mody, Java, Ustawienia).\r\nJak dzia艂a:\r\nKlikni臋cie w dan膮 zak艂adk臋 powoduje prze艂adowanie g艂贸wnego obszaru z tre艣ci膮 odpowiadaj膮c膮 wybranej sekcji.\r\nZak艂adki maj膮 animacj臋 przej艣cia (fade-in, transformacja) oraz wizualne wyr贸偶nienie aktywnej zak艂adki.\r\nPo co to: Umo偶liwia 艂atwe nawigowanie pomi臋dzy kluczowymi funkcjami panelu.\r\nB. Panel Boczy\r\nElementy: Lista serwer贸w (encje), opcja dodawania/usuwania serwer贸w, szybki podgl膮d statusu (zielony 鈥?online, czerwony 鈥?offline, 偶贸艂ty 鈥?restart/awaria).\r\nJak dzia艂a:\r\nKlikni臋cie na serwer wy艣wietla szczeg贸艂owe informacje w g艂贸wnej cz臋艣ci panelu.\r\nMenu kontekstowe (prawy klik) z szybkimi akcjami, takimi jak uruchom, zatrzymaj, restart, usuwanie.\r\nPo co to: Umo偶liwia szybki wyb贸r i zarz膮dzanie wieloma serwerami.\r\nC. G艂贸wna Tre艣膰 (Body)\r\nPodzielona na sekcje odpowiadaj膮ce wybranej zak艂adce:\r\n\r\nDashboard:\r\n\r\nElementy: Podsumowanie statusu serwera, wska藕niki (ping, zu偶ycie zasob贸w), wykresy, statystyki.\r\nJak dzia艂a: Dane s膮 aktualizowane w czasie rzeczywistym (np. przez WebSocket).\r\nPo co to: Daje szybki wgl膮d w stan serwera, co pomaga w diagnozie problem贸w.\r\nSterowanie:\r\n\r\nElementy: Przyciski akcji (Uruchom, Zatrzymaj, Restart, Ubij).\r\nJak dzia艂a: Po klikni臋ciu wywo艂uj膮 funkcje placeholder (do podpi臋cia do API) 鈥?animacje zmiany stanu, logi akcji.\r\nPo co to: Pozwala na manualne sterowanie prac膮 serwera.\r\nKonfiguracja (Server.properties & JSON):\r\n\r\nElementy: Formularze do edycji wszystkich opcji z pliku server.properties oraz plik贸w typu ops.json, whitelist.json, banned.json itp.\r\nJak dzia艂a:\r\nFormularze z inputami, selectami, checkboxami 鈥?ka偶da zmiana wysy艂ana jest przez placeholder (mo偶liwo艣膰 walidacji danych, podgl膮d zmian).\r\nPodzia艂 na sekcje: Og贸lne, Rozgrywka, 艢wiat, Sie膰.\r\nPo co to: Umo偶liwia szybkie i intuicyjne modyfikowanie ustawie艅 serwera bez r臋cznej edycji plik贸w.\r\nZarz膮dzanie 艢wiatami:\r\n\r\nElementy: Lista 艣wiat贸w, opcje backupu, przywracania, 艂adowania/usuwania 艣wiat贸w.\r\nJak dzia艂a:\r\nKa偶dy 艣wiat ma przyciski akcji 鈥?backup (uruchamia funkcj臋 backupu, placeholder dla procesu), edycja, usuwanie.\r\nPo co to: Zarz膮dzanie 艣wiatami jest kluczowe przy wielo艣wiatowych serwerach 鈥?backup i mo偶liwo艣膰 przywracania pozwalaj膮 na ochron臋 danych.\r\nKonsola/Logi:\r\n\r\nElementy: Terminal z dynamicznym wy艣wietlaniem log贸w, formularz do wysy艂ania komend, opcje filtrowania log贸w (INFO, WARN, ERROR).\r\nJak dzia艂a:\r\nLogi s膮 aktualizowane w czasie rzeczywistym, scrollowane, z mo偶liwo艣ci膮 wyczyszczenia.\r\nWysy艂anie komend poprzez formularz 鈥?placeholder wysy艂a dane do serwera.\r\nPo co to: Umo偶liwia administratorowi monitorowanie pracy serwera oraz debugowanie w czasie rzeczywistym.\r\nZarz膮dzanie Plikami:\r\n\r\nElementy: Mened偶er plik贸w z widokiem drzewiastym, obs艂ug膮 kontekstowego menu (zmiana nazwy, usuwanie, otwieranie katalog贸w).\r\nJak dzia艂a:\r\nDynamiczne pobieranie struktury plik贸w, sortowanie, animacje otwierania katalog贸w.\r\nPo co to: Umo偶liwia zarz膮dzanie wszystkimi plikami serwera, co jest kluczowe przy konfiguracjach, backupie czy modyfikacjach.\r\nZarz膮dzanie Graczami:\r\n\r\nElementy: Sekcje: Banned, Whitelist, Ops 鈥?wy艣wietlanie list, mo偶liwo艣膰 dodawania/edycji/usuwania wpis贸w.\r\nJak dzia艂a:\r\nKa偶da sekcja zawiera tabel臋 z danymi (np. nick, pow贸d, poziom, przyciski usuwania) i przycisk 鈥濪odaj鈥?otwieraj膮cy modal do wprowadzenia danych.\r\nPo co to: Umo偶liwia szybkie zarz膮dzanie listami graczy, co jest niezb臋dne dla bezpiecze艅stwa i porz膮dku na serwerze.\r\nModyfikacje (Mods):\r\n\r\nElementy: Lista mod贸w, mo偶liwo艣膰 przesy艂ania nowych mod贸w, wyszukiwania, w艂膮czania/wy艂膮czania, usuwania.\r\nJak dzia艂a:\r\nInterfejs do uploadu plik贸w .jar, filtrowanie listy mod贸w, dynamiczna zmiana stanu (w艂膮czony/wy艂膮czony).\r\nPo co to: Modyfikacje cz臋sto zmieniaj膮 funkcjonalno艣膰 serwera 鈥?wa偶ne, aby mie膰 kontrol臋 nad tym, jakie mody s膮 aktywne.\r\nUstawienia Javy:\r\n\r\nElementy: Wyb贸r wersji Javy (select), ustawienia zasob贸w (suwak RAM, pole tekstowe na dodatkowe parametry), upload pliku JAR.\r\nJak dzia艂a:\r\nDynamiczna aktualizacja opcji 鈥?po zmianie ustawie艅 wysy艂any jest komunikat do serwera.\r\nPo co to: Kluczowe dla optymalizacji dzia艂ania serwera, szczeg贸lnie przy du偶ej liczbie graczy lub przy specyficznych wymaganiach mod贸w.\r\nUstawienia Og贸lne (Wygl膮d, Personalizacja):\r\n\r\nElementy: Edycja wygl膮du interfejsu, zmiana ikon, motyw贸w kolorystycznych, ustawienia panelu (np. uk艂ad, animacje).\r\nJak dzia艂a:\r\nU偶ytkownik mo偶e przes艂a膰 now膮 ikon臋, zmieni膰 kolory i ustawi膰 preferencje, kt贸re b臋d膮 zapisywane w konfiguracji.\r\nPo co to: Umo偶liwia dostosowanie interfejsu do indywidualnych preferencji, co zwi臋ksza komfort pracy.\r\n3. Szczeg贸艂owy Plan TODO 鈥?Lista Funkcji\r\n3.1. Modu艂 Nawigacji i Interfejsu\r\nZak艂adki i nag艂贸wek:\r\n Implementacja zak艂adek:\r\nPrze艂膮czanie widocznych paneli.\r\nAnimacja aktywnej zak艂adki (fade-in, transformacja).\r\nDlaczego? Umo偶liwia przejrzyst膮 i intuicyjn膮 nawigacj臋 pomi臋dzy sekcjami.\r\n Panel boczny:\r\nLista serwer贸w z dynamicznym statusiem (ikonki, kolory).\r\nDodawanie/usuwanie serwer贸w.\r\nMenu kontekstowe (prawy klik) z szybkim dost臋pem do akcji.\r\nDlaczego? U艂atwia szybkie wybieranie i zarz膮dzanie wieloma serwerami.\r\n3.2. Dashboard\r\n Status serwera i statystyki:\r\nWska藕niki takie jak ping, zu偶ycie CPU/RAM, liczba graczy.\r\nWykresy i wizualizacje (np. pasek post臋pu, diagramy ko艂owe).\r\nDlaczego? Pozwala na szybkie rozpoznanie aktualnego stanu serwera oraz identyfikacj臋 potencjalnych problem贸w.\r\n3.3. Sterowanie Serwerem\r\n Przyciski akcji:\r\n\r\nUruchom, Zatrzymaj, Restart, Ubij.\r\nAnimacje przycisk贸w (hover, klikni臋cie).\r\nPlaceholdery 鈥?wy艣wietlanie alert贸w lub log贸w po klikni臋ciu.\r\nDlaczego? Podstawowa funkcjonalno艣膰 zarz膮dzania prac膮 serwera.\r\n Feedback wizualny:\r\n\r\nZmiana koloru statusu serwera, animacja przej艣cia przy zmianie stanu.\r\nDlaczego? U偶ytkownik od razu widzi rezultat wykonanej akcji.\r\n3.4. Konfiguracja Serwera\r\n Formularz konfiguracji:\r\n\r\nWszystkie opcje z server.properties (motd, max players, port, online-mode, spawn protection, difficulty, gamemode, command block, whitelist, level-seed, itd.).\r\nPodzia艂 na sekcje (Og贸lne, Rozgrywka, 艢wiat, Sie膰).\r\nDynamiczne walidacje danych (np. zakresy warto艣ci, formaty tekstowe).\r\nDlaczego? Umo偶liwia administratorowi 艂atw膮 modyfikacj臋 ustawie艅 bez edycji plik贸w r臋cznie.\r\n Obs艂uga plik贸w JSON:\r\n\r\nEdycja list (ops, whitelist, banned, banned IP) za pomoc膮 edytor贸w tabelarycznych.\r\nModal do dodawania nowego wpisu.\r\nDlaczego? Kluczowe dla bezpiecze艅stwa i zarz膮dzania dost臋pem do serwera.\r\n3.5. Zarz膮dzanie 艢wiatami\r\n Lista 艣wiat贸w:\r\nWy艣wietlanie listy dost臋pnych 艣wiat贸w, wraz z opcjami backupu, przywracania, edycji i usuwania.\r\nAnimowane przyciski do wykonania akcji (np. backup 鈥?placeholder z komunikatem).\r\nDlaczego? Umo偶liwia 艂atwe zarz膮dzanie danymi 艣wiata oraz zabezpieczenie przed utrat膮 danych.\r\n3.6. Konsola i Logi\r\n Konsola serwera:\r\n\r\nDynamiczne wy艣wietlanie log贸w, mo偶liwo艣膰 filtrowania (INFO, WARN, ERROR).\r\nFormularz do wysy艂ania komend 鈥?obs艂uga enter oraz przycisk wy艣lij.\r\nOpcja wyczyszczenia konsoli.\r\nDlaczego? Niezb臋dne do monitorowania pracy serwera i debugowania.\r\n Sekcja log贸w:\r\n\r\nWyb贸r logu z listy (select), podgl膮d zawarto艣ci.\r\nKolorowanie linii log贸w w zale偶no艣ci od typu komunikatu.\r\nDlaczego? Pozwala na szybkie wyszukiwanie b艂臋d贸w i analizy problem贸w.\r\n3.7. Zarz膮dzanie Plikami\r\n Mened偶er plik贸w:\r\nWidok drzewiasty, sortowanie plik贸w i katalog贸w.\r\nObs艂uga menu kontekstowego (prawy klik) 鈥?zmiana nazwy, usuwanie, otwieranie katalog贸w.\r\nScrollbar z niestandardowym stylem.\r\nDlaczego? Umo偶liwia administrowanie plikami serwera, co jest kluczowe przy modyfikacjach, backupach i aktualizacjach.\r\n3.8. Zarz膮dzanie Graczami\r\n Modu艂y dla:\r\nBanned, Whitelist, Operatorzy.\r\nWy艣wietlanie tabel z danymi, przyciski usuwania i dodawania.\r\nModal do dodawania nowych wpis贸w z walidacj膮 danych.\r\nDlaczego? Kontrola nad list膮 graczy jest niezb臋dna dla utrzymania porz膮dku i bezpiecze艅stwa na serwerze.\r\n3.9. Zarz膮dzanie Modami\r\n Panel modyfikacji:\r\nLista dost臋pnych mod贸w z wyszukiwark膮.\r\nUpload nowych mod贸w (.jar) oraz przyciski do w艂膮czania/wy艂膮czania i usuwania.\r\nDynamiczne aktualizacje stanu (czy mod jest aktywny, czy nie).\r\nDlaczego? Modu艂y mog膮 znacz膮co zmienia膰 funkcjonalno艣膰 serwera 鈥?administrator musi mie膰 pe艂n膮 kontrol臋 nad ich stanem.\r\n3.10. Ustawienia Javy\r\n Konfiguracja Javy:\r\nWyb贸r wersji Javy (select z dost臋pnych opcji pobieranych dynamicznie).\r\nUstawienia zasob贸w 鈥?suwak do wyboru ilo艣ci RAM, pole do wpisania dodatkowych parametr贸w.\r\nUpload pliku JAR serwera 鈥?podgl膮d aktualnie wybranego pliku.\r\nDlaczego? Poprawne ustawienia Javy s膮 krytyczne dla wydajno艣ci i stabilno艣ci serwera.\r\n3.11. Dodatkowe Ustawienia i Personalizacja\r\n Personalizacja interfejsu:\r\nMo偶liwo艣膰 zmiany motywu kolorystycznego, przesy艂ania nowych ikon, ustawiania w艂asnych preferencji wygl膮du.\r\nOpcje konfiguracji animacji i efekt贸w wizualnych (np. fade-in, hover).\r\nDlaczego? Pozwala na dostosowanie panelu do indywidualnych preferencji administratora, co wp艂ywa na komfort pracy.\r\n3.12. Komunikacja w Czasie Rzeczywistym\r\n Integracja WebSocket:\r\nPo艂膮czenie z serwerem w czasie rzeczywistym do przesy艂ania log贸w, status贸w, polece艅.\r\nObs艂uga zdarze艅: aktualizacja listy serwer贸w, log贸w, statusu (dynamiczna synchronizacja).\r\nDlaczego? Umo偶liwia natychmiastow膮 reakcj臋 na zmiany i bie偶膮ce monitorowanie serwera.\r\n3.13. Backup i Przywracanie Konfiguracji\r\n Modu艂 backupu:\r\nFunkcje backupu 艣wiata, konfiguracji i plik贸w.\r\nMechanizm tworzenia kopii zapasowych (placeholder 鈥?do p贸藕niejszej implementacji z realnym API lub zapisem na dysku).\r\nOpcja przywracania z backupu.\r\nDlaczego? Ochrona danych i mo偶liwo艣膰 przywr贸cenia stanu serwera w przypadku awarii.\r\n3.14. Dodatkowe Elementy UI\r\n Menu kontekstowe:\r\n\r\nDla serwer贸w, plik贸w, wpis贸w w tabelach 鈥?dynamiczne menu z animacjami (fade-in).\r\nDlaczego? U艂atwia wykonywanie dodatkowych akcji bez konieczno艣ci klikania wielu przycisk贸w.\r\n Animacje i responsywno艣膰:\r\n\r\nEfekty wizualne przy przej艣ciach mi臋dzy sekcjami, przyciskach, menu.\r\nResponsywny design 鈥?dostosowanie do r贸偶nych rozdzielczo艣ci i urz膮dze艅.\r\nDlaczego? Poprawia estetyk臋 interfejsu i komfort u偶ytkowania, szczeg贸lnie na urz膮dzeniach mobilnych.\r\n4. Podsumowanie 鈥濸o Co To?鈥漒r\nIntegracja i centralizacja: Wszystkie kluczowe funkcje zarz膮dzania serwerem w jednym miejscu 鈥?nie musisz r臋cznie edytowa膰 plik贸w ani korzysta膰 z kilku aplikacji.\r\nU艂atwienie administracji: Intuicyjny interfejs pozwala na szybsze reagowanie w sytuacjach awaryjnych oraz lepsz膮 diagnostyk臋 problem贸w.\r\nBezpiecze艅stwo i backup: Funkcje backupu, zarz膮dzania graczami i konfiguracjami pomagaj膮 zabezpieczy膰 serwer przed niepo偶膮danymi zmianami i atakami.\r\nPersonalizacja i estetyka: Mo偶liwo艣膰 dostosowania wygl膮du i ustawie艅 pozwala na stworzenie 艣rodowiska, kt贸re najlepiej odpowiada Twoim potrzebom.\r\nReal-time monitoring: Integracja z WebSocket zapewnia natychmiastow膮 aktualizacj臋 danych, co jest kluczowe przy dynamicznym 艣rodowisku serwerowym.\r\n5. Kolejne Kroki\r\nProjektowanie UI:\r\n\r\nStworzy膰 makiety i prototypy poszczeg贸lnych sekcji panelu.\r\nOkre艣li膰 szczeg贸艂ow膮 palet臋 kolor贸w, animacje i responsywne zachowania.\r\nImplementacja podstawowych funkcji (placeholdery):\r\n\r\nZacz膮膰 od modu艂贸w dashboardu, sterowania i konfiguracji.\r\nZintegrowa膰 podstawowe funkcje WebSocket.\r\nRozbudowa funkcji zaawansowanych:\r\n\r\nBackup 艣wiata, zarz膮dzanie plikami, obs艂uga log贸w.\r\nImplementacja zaawansowanych opcji konfiguracji i edycji plik贸w JSON.\r\nTesty i optymalizacja:\r\n\r\nPrzeprowadzi膰 testy interfejsu pod k膮tem responsywno艣ci, szybko艣ci aktualizacji oraz intuicyjno艣ci.\r\nDostosowa膰 animacje i efekty wizualne.\r\nIntegracja z serwerem Minecraft:\r\n\r\nPo艂膮czenie z backendem, kt贸ry zarz膮dza serwerami Minecraft (API, WebSocket, operacje na plikach).\r\nUpewni膰 si臋, 偶e wszystkie funkcje (uruchamianie, zatrzymywanie, backup, itd.) dzia艂aj膮 zgodnie z za艂o偶eniami.",
- "Path": "/TODO.MD",
- "SizeKB": "16,39"
- },
- "/logs/minecraft_2025-03-16T14-19-43.410Z.log": {
- "Path": "/logs/minecraft_2025-03-16T14-19-43.410Z.log",
- "SizeKB": "0,26"
- },
- "/logs/server_2025-03-16T14-19-43.410Z.log": {
- "Path": "/logs/server_2025-03-16T14-19-43.410Z.log",
- "SizeKB": "6,50"
- },
- "/logs/debug_2025-03-22T17-46-05.557Z.log": {
- "Path": "/logs/debug_2025-03-22T17-46-05.557Z.log",
- "SizeKB": "15,23"
- },
- "/server/utils/configLoader.js": {
- "Content": "const fs = require('fs').promises;\r\nconst path = require('path');\r\nconst { log } = require('./logger');\r\n\r\nasync function loadConfig() {\r\n const configPath = path.join(__dirname, '../config.json');\r\n try {\r\n const data = await fs.readFile(configPath, 'utf8');\r\n return JSON.parse(data);\r\n } catch (e) {\r\n log('warn', '[CONFIG_LOAD] Brak config.json, u偶ywam domy艣lnych ustawie艅');\r\n return { javaToDownload: ['8', '11', '16', '17', '20'] };\r\n }\r\n}\r\n\r\nmodule.exports = { loadConfig };",
- "Path": "/server/utils/configLoader.js",
- "SizeKB": "0,51"
- },
- "/logs/minecraft_2025-03-16T15-11-15.055Z.log": {
- "Path": "/logs/minecraft_2025-03-16T15-11-15.055Z.log",
- "SizeKB": "0,92"
- },
- "/logs/minecraft.log": {
- "Path": "/logs/minecraft.log",
- "SizeKB": "0,76"
- },
- "/public/img/icon_16.png": {
- "Path": "/public/img/icon_16.png",
- "SizeKB": "0,58"
- },
- "/server/utils/logger.js": {
- "Content": "const fs = require('fs').promises;\r\nconst path = require('path');\r\n\r\nconst logsDir = path.join(__dirname, '../../logs');\r\n\r\n// Tworzymy folder logs, je艣li nie istnieje\r\nasync function ensureLogsDir() {\r\n await fs.mkdir(logsDir, { recursive: true }).catch(() => {});\r\n}\r\n\r\n// Rotacja log贸w przy starcie\r\nasync function rotateLogs() {\r\n await ensureLogsDir();\r\n const timestamp = new Date().toISOString().replace(/:/g, '-');\r\n const logFiles = ['app.log', 'error.log', 'minecraft.log', 'server.log', 'debug.log'];\r\n\r\n for (const file of logFiles) {\r\n const logPath = path.join(logsDir, file);\r\n if (await fs.access(logPath).then(() => true).catch(() => false)) {\r\n const newLogPath = path.join(logsDir, `${file.split('.')[0]}_${timestamp}.log`);\r\n await fs.rename(logPath, newLogPath);\r\n await log('server', 'info', `[LOG_ROTATE] Przeniesiono ${file} do ${newLogPath}`); // Dodano 'info'\r\n }\r\n }\r\n}\r\n\r\n// Funkcja logowania z kategoriami\r\nasync function log(category, level, message, error) {\r\n const timestamp = new Date().toISOString();\r\n const output = `[${timestamp}] [${level.toUpperCase()}] ${message}${error ? `: ${error}` : ''}`;\r\n \r\n // Wyb贸r pliku na podstawie kategorii\r\n let logFile;\r\n switch (category.toLowerCase()) {\r\n case 'minecraft':\r\n logFile = 'minecraft.log';\r\n break;\r\n case 'server':\r\n logFile = 'server.log';\r\n break;\r\n case 'debug':\r\n logFile = 'debug.log';\r\n break;\r\n case 'error':\r\n logFile = 'error.log';\r\n break;\r\n default:\r\n logFile = 'app.log'; // Fallback\r\n }\r\n\r\n // Je艣li poziom to error, zawsze do error.log\r\n if (level.toLowerCase() === 'error') {\r\n logFile = 'error.log';\r\n }\r\n\r\n const logPath = path.join(logsDir, logFile);\r\n \r\n try {\r\n await fs.appendFile(logPath, output + '\\n');\r\n } catch (e) {\r\n console.error(`[LOGGER_ERROR] Nie uda艂o si臋 zapisa膰 do ${logFile}: ${e}`);\r\n }\r\n\r\n // Tylko b艂臋dy w konsoli\r\n if (level.toLowerCase() === 'error') {\r\n console.log(output);\r\n }\r\n}\r\n\r\n// Rotacja przy starcie\r\nrotateLogs().then(() => {\r\n log('server', 'info', '[LOGGER_INIT] Logger zainicjalizowany, logi id膮 do plik贸w!');\r\n});\r\n\r\nmodule.exports = { log };",
- "Path": "/server/utils/logger.js",
- "SizeKB": "2,33"
- },
- "/logs/app_2025-03-16T19-09-40.484Z.log": {
- "Path": "/logs/app_2025-03-16T19-09-40.484Z.log",
- "SizeKB": "13,47"
- },
- "/logs/minecraft_2025-03-22T17-46-05.557Z.log": {
- "Path": "/logs/minecraft_2025-03-22T17-46-05.557Z.log",
- "SizeKB": "0,08"
- },
- "/logs/error_2025-04-16T15-30-48.625Z.log": {
- "Path": "/logs/error_2025-04-16T15-30-48.625Z.log",
- "SizeKB": "0,08"
- },
- "/logs/debug_2025-04-16T15-48-07.953Z.log": {
- "Path": "/logs/debug_2025-04-16T15-48-07.953Z.log",
- "SizeKB": "10,74"
- },
- "/logs/debug_2025-04-16T15-38-13.014Z.log": {
- "Path": "/logs/debug_2025-04-16T15-38-13.014Z.log",
- "SizeKB": "12,99"
- },
- "/logs/server_2025-04-16T15-30-48.625Z.log": {
- "Path": "/logs/server_2025-04-16T15-30-48.625Z.log",
- "SizeKB": "8,90"
- },
- "/logs/minecraft_2025-04-16T15-08-42.487Z.log": {
- "Path": "/logs/minecraft_2025-04-16T15-08-42.487Z.log",
- "SizeKB": "0,08"
- },
- "/_start.sh": {
- "Content": null,
- "Path": "/_start.sh",
- "SizeKB": "0,00"
- },
- "/logs/app_2025-04-16T15-38-13.014Z.log": {
- "Path": "/logs/app_2025-04-16T15-38-13.014Z.log",
- "SizeKB": "0,10"
- },
- "/logs/server_2025-03-16T15-02-19.600Z.log": {
- "Path": "/logs/server_2025-03-16T15-02-19.600Z.log",
- "SizeKB": "4,39"
- },
- "/server/controllers/backupManager.js": {
- "Content": "const fsPromises = require('fs').promises; // Dla Promise\r\nconst fs = require('fs'); // Dla createWriteStream\r\nconst path = require('path');\r\nconst archiver = require('archiver');\r\nconst { log } = require('../utils/logger');\r\n\r\nclass BackupManager {\r\n constructor(serverManager) {\r\n this.serverManager = serverManager;\r\n }\r\n\r\n async createBackup(serverId) {\r\n const server = this.serverManager.getServer(serverId);\r\n if (!server) {\r\n log('backup', 'error', `[BACKUP_ERROR] Serwer ${serverId} nie istnieje`);\r\n throw new Error('Serwer nie istnieje');\r\n }\r\n\r\n const serverPath = path.join(__dirname, '../servers', serverId);\r\n const propertiesPath = path.join(serverPath, 'server.properties');\r\n let levelName = 'world';\r\n\r\n try {\r\n // Odczyt level-name z server.properties\r\n const properties = await fsPromises.readFile(propertiesPath, 'utf8');\r\n const levelMatch = properties.match(/level-name=(.*)/);\r\n if (levelMatch) levelName = levelMatch[1].trim();\r\n log('backup', 'info', `[BACKUP] Odczytano level-name: ${levelName} dla ${serverId}`);\r\n } catch (err) {\r\n log('backup', 'warn', `[BACKUP_WARN] Nie uda艂o si臋 odczyta膰 server.properties dla ${serverId}, u偶ywam domy艣lnego 艣wiata: ${levelName}`, err.message);\r\n }\r\n\r\n // Je艣li serwer dzia艂a, wydaj save-all\r\n if (server.process) {\r\n log('backup', 'info', `[BACKUP] Wysy艂am save-all do ${serverId}`);\r\n server.process.stdin.write('save-all\\n');\r\n await new Promise((resolve) => setTimeout(resolve, 2000)); // Czekaj 2s\r\n }\r\n\r\n // Tworzenie folderu backup\r\n const backupDir = path.join(serverPath, 'backup');\r\n await fsPromises.mkdir(backupDir, { recursive: true });\r\n\r\n // Tworzenie ZIP-a\r\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-');\r\n const outputPath = path.join(backupDir, `backup-${timestamp}.zip`);\r\n const output = fs.createWriteStream(outputPath); // U偶ywamy pe艂nego fs\r\n const archive = archiver('zip', { zlib: { level: 9 } });\r\n\r\n log('backup', 'info', `[BACKUP] Tworz臋 backup dla ${serverId}: ${outputPath}`);\r\n\r\n return new Promise((resolve, reject) => {\r\n output.on('close', () => {\r\n log('backup', 'info', `[BACKUP_SUCCESS] Backup dla ${serverId} uko艅czony: ${outputPath}`);\r\n resolve(outputPath);\r\n });\r\n archive.on('error', (err) => {\r\n log('backup', 'error', `[BACKUP_ERROR] B艂膮d zipowania dla ${serverId}`, err.message);\r\n reject(err);\r\n });\r\n\r\n archive.pipe(output);\r\n archive.directory(path.join(serverPath, levelName), false);\r\n archive.finalize();\r\n });\r\n }\r\n}\r\n\r\nmodule.exports = BackupManager;",
- "Path": "/server/controllers/backupManager.js",
- "SizeKB": "2,64"
- },
- "/logs/server_2025-04-16T15-08-42.487Z.log": {
- "Path": "/logs/server_2025-04-16T15-08-42.487Z.log",
- "SizeKB": "2,98"
- },
- "/logs/debug_2025-04-16T15-40-49.225Z.log": {
- "Path": "/logs/debug_2025-04-16T15-40-49.225Z.log",
- "SizeKB": "10,74"
- },
- "/logs/server_2025-03-16T15-00-13.680Z.log": {
- "Path": "/logs/server_2025-03-16T15-00-13.680Z.log",
- "SizeKB": "4,92"
- },
- "/logs/debug_2025-04-16T15-08-42.487Z.log": {
- "Path": "/logs/debug_2025-04-16T15-08-42.487Z.log",
- "SizeKB": "10,74"
- },
- "/logs/server_2025-03-16T14-07-15.354Z.log": {
- "Path": "/logs/server_2025-03-16T14-07-15.354Z.log",
- "SizeKB": "0,75"
- },
- "/logs/minecraft_2025-03-16T14-50-54.242Z.log": {
- "Path": "/logs/minecraft_2025-03-16T14-50-54.242Z.log",
- "SizeKB": "0,17"
- },
- "/.vscode/tasks.json": {
- "Content": "{\r\n \"version\": \"2.0.0\",\r\n \"tasks\": [\r\n {\r\n \"label\": \"Start Server\",\r\n \"type\": \"shell\",\r\n \"command\": \"node ${workspaceFolder}/server/server.js\",\r\n \"group\": {\r\n \"kind\": \"build\",\r\n \"isDefault\": true\r\n },\r\n \"problemMatcher\": [],\r\n \"presentation\": {\r\n \"echo\": true,\r\n \"reveal\": \"always\",\r\n \"focus\": false,\r\n \"panel\": \"shared\"\r\n }\r\n }\r\n ]\r\n}",
- "Path": "/.vscode/tasks.json",
- "SizeKB": "0,42"
- },
- "/logs/server.log": {
- "Path": "/logs/server.log",
- "SizeKB": "6,78"
- },
- "/public/css/resourceMonitor.css": {
- "Content": ".gauge-container {\r\n position: relative;\r\n width: 150px;\r\n height: 75px;\r\n margin: 10px;\r\n overflow: hidden;\r\n background: #383838;\r\n border-radius: 5px;\r\n}\r\n\r\n.gauge {\r\n width: 100%;\r\n height: 150px;\r\n background: radial-gradient(circle, #444 50%, #2d2d2d 100%);\r\n border-radius: 150px 150px 0 0;\r\n position: absolute;\r\n bottom: 0;\r\n clip-path: polygon(0 100%, 100% 100%, 100% 0, 0 0);\r\n z-index: 1;\r\n}\r\n\r\n.gauge-needle {\r\n width: 3px;\r\n height: 60px;\r\n background: #ff4500;\r\n position: absolute;\r\n bottom: 0;\r\n left: 50%;\r\n transform-origin: bottom center;\r\n transform: rotate(-90deg);\r\n transition: transform 1s ease-out;\r\n z-index: 2;\r\n}\r\n\r\n.gauge-label {\r\n position: relative;\r\n text-align: center;\r\n font-size: 14px;\r\n color: #d4d4d4;\r\n margin-top: 85px;\r\n z-index: 3;\r\n background: rgba(0, 0, 0, 0.8);\r\n padding: 3px 6px;\r\n border-radius: 3px;\r\n white-space: nowrap;\r\n}\r\n\r\n.gauge-value {\r\n position: relative;\r\n text-align: center;\r\n font-size: 16px;\r\n color: #ff4500;\r\n margin-top: 5px;\r\n z-index: 4;\r\n background: rgba(0, 0, 0, 0.6);\r\n padding: 2px 5px;\r\n border-radius: 3px;\r\n white-space: nowrap;\r\n min-width: 80px;\r\n display: block;\r\n}",
- "Path": "/public/css/resourceMonitor.css",
- "SizeKB": "1,26"
- },
- "/server/controllers/resourceMonitor.js": {
- "Content": "const { exec } = require('child_process');\r\nconst { log } = require('../utils/logger');\r\n\r\nclass ResourceMonitor {\r\n constructor(serversProvider, wsSender) {\r\n this.serversProvider = serversProvider;\r\n this.wsSender = wsSender;\r\n this.monitoringInterval = null;\r\n }\r\n\r\n startMonitoring() {\r\n this.monitoringInterval = setInterval(() => {\r\n const servers = this.serversProvider.getRunningServers();\r\n servers.forEach(({ id, pid }) => {\r\n if (!pid) {\r\n log('resource', 'warn', `[MONITOR_NO_PID] Brak PID dla ${id}, kurwa! 馃槨`);\r\n this.wsSender.sendToAll({\r\n type: 'resourceUpdate',\r\n serverId: id,\r\n cpu: 0,\r\n ram: 0\r\n });\r\n return;\r\n }\r\n\r\n this.getResourceUsage(pid, (err, { cpu, ram }) => {\r\n if (err) {\r\n log('resource', 'error', `[RESOURCE_ERROR] B艂膮d przy zasobach dla ${id}`, err.message);\r\n this.wsSender.sendToAll({\r\n type: 'resourceUpdate',\r\n serverId: id,\r\n cpu: 0,\r\n ram: 0\r\n });\r\n return;\r\n }\r\n log('resource', 'info', `[MONITOR] Zasoby dla ${id}: CPU ${cpu}%, RAM ${ram}MB 馃敟`);\r\n this.wsSender.sendToAll({\r\n type: 'resourceUpdate',\r\n serverId: id,\r\n cpu: cpu || 0,\r\n ram: ram || 0\r\n });\r\n });\r\n });\r\n }, 2000); // Co 2 sekundy\r\n }\r\n\r\n stopMonitoring() {\r\n if (this.monitoringInterval) {\r\n clearInterval(this.monitoringInterval);\r\n }\r\n }\r\n\r\n getResourceUsage(pid, callback) {\r\n // CPU przez wmic 鈥?sumujemy KernelModeTime i UserModeTime\r\n const cpuCommand = `wmic process where ProcessId=${pid} get KernelModeTime,UserModeTime`;\r\n // RAM przez wmic 鈥?WorkingSetSize (w bajtach)\r\n const ramCommand = `wmic process where ProcessId=${pid} get WorkingSetSize`;\r\n\r\n let cpuUsage, ramUsage;\r\n\r\n exec(cpuCommand, (err, stdout, stderr) => {\r\n if (err || stderr) {\r\n log('resource', 'error', `[CPU_ERROR] B艂膮d przy CPU dla PID ${pid}`, err?.message || stderr);\r\n cpuUsage = 0;\r\n } else {\r\n const lines = stdout.trim().split('\\n');\r\n if (lines.length > 1) {\r\n const values = lines[1].trim().split(/\\s+/);\r\n const kernelTime = parseInt(values[0], 10) || 0;\r\n const userTime = parseInt(values[1], 10) || 0;\r\n // Sumujemy czas procesora (w 100ns), przeliczamy na sekundy i procenty\r\n const totalTime = (kernelTime + userTime) / 10000000; // Przeliczamy na sekundy\r\n const elapsedTime = 2; // Interwa艂 monitorowania (2 sekundy)\r\n cpuUsage = Math.min(Math.round((totalTime / (elapsedTime * 8)) * 100), 100); // 8 rdzeni\r\n if (isNaN(cpuUsage)) cpuUsage = 0;\r\n log('debug', 'info', `[CPU_DEBUG] PID ${pid}: KernelTime ${kernelTime}, UserTime ${userTime}, CPU ${cpuUsage}%`);\r\n } else {\r\n cpuUsage = 0;\r\n log('debug', 'info', `[CPU_DEBUG] PID ${pid}: Brak danych CPU, ustawiam 0%`);\r\n }\r\n }\r\n\r\n exec(ramCommand, (err, stdout, stderr) => {\r\n if (err || stderr) {\r\n log('resource', 'error', `[RAM_ERROR] B艂膮d przy RAM dla PID ${pid}`, err?.message || stderr);\r\n ramUsage = 0;\r\n } else {\r\n const lines = stdout.trim().split('\\n');\r\n if (lines.length > 1) {\r\n const ramBytes = parseInt(lines[1].trim(), 10) || 0;\r\n ramUsage = Math.round(ramBytes / 1024 / 1024); // Przeliczamy na MB\r\n if (ramUsage < 10) {\r\n log('resource', 'warn', `[RAM_ANOMALY] RAM ${ramUsage}MB dla PID ${pid} za ma艂e, resetuj臋!`);\r\n ramUsage = 0;\r\n }\r\n log('debug', 'info', `[RAM_DEBUG] PID ${pid}: WorkingSetSize ${ramBytes} bajt贸w, RAM ${ramUsage}MB`);\r\n } else {\r\n ramUsage = 0;\r\n log('debug', 'info', `[RAM_DEBUG] PID ${pid}: Brak danych RAM, ustawiam 0MB`);\r\n }\r\n }\r\n\r\n callback(null, { cpu: cpuUsage, ram: ramUsage });\r\n });\r\n });\r\n }\r\n}\r\n\r\nmodule.exports = ResourceMonitor;",
- "Path": "/server/controllers/resourceMonitor.js",
- "SizeKB": "4,87"
- },
- "/logs/minecraft_2025-04-16T15-48-07.953Z.log": {
- "Path": "/logs/minecraft_2025-04-16T15-48-07.953Z.log",
- "SizeKB": "0,16"
- },
- "/_start.bat": {
- "Content": "node server/server.js",
- "Path": "/_start.bat",
- "SizeKB": "0,02"
- },
- "/logs/server_2025-03-16T15-08-18.725Z.log": {
- "Path": "/logs/server_2025-03-16T15-08-18.725Z.log",
- "SizeKB": "3,73"
- },
- "/logs/server_2025-03-16T15-11-15.055Z.log": {
- "Path": "/logs/server_2025-03-16T15-11-15.055Z.log",
- "SizeKB": "4,92"
- },
- "/logs/app_2025-04-16T15-30-48.625Z.log": {
- "Path": "/logs/app_2025-04-16T15-30-48.625Z.log",
- "SizeKB": "6,79"
- },
- "/logs/app_2025-04-16T15-46-59.644Z.log": {
- "Path": "/logs/app_2025-04-16T15-46-59.644Z.log",
- "SizeKB": "5,56"
- },
- "/server/controllers/fileManager.js": {
- "Content": "const fs = require('fs').promises;\r\nconst path = require('path');\r\nconst { log } = require('../utils/logger');\r\nconst { servers, saveInstance, loadServerFiles } = require('./serverManager');\r\n\r\nasync function uploadJar(serverName, dataUrl, filename) {\r\n if (servers[serverName].running) {\r\n log('error', `[JAR_UPLOAD_ERROR] Serwer ${serverName} dzia艂a, zatrzymaj go przed zmian膮 JAR!`);\r\n return;\r\n }\r\n const base64 = dataUrl.split(',')[1];\r\n const buffer = Buffer.from(base64, 'base64');\r\n const jarPath = path.join(servers[serverName].dir, filename || 'server.jar');\r\n await fs.writeFile(jarPath, buffer);\r\n servers[serverName].jar = filename || 'server.jar';\r\n log('info', `[JAR_UPLOAD_DEBUG] Zapisano JAR w: ${jarPath}`);\r\n}\r\n\r\nasync function uploadIcon(serverName, dataUrl) {\r\n if (servers[serverName].running) {\r\n log('error', `[ICON_UPLOAD_ERROR] Serwer ${serverName} dzia艂a, zatrzymaj go przed zmian膮 ikony!`);\r\n return;\r\n }\r\n const base64 = dataUrl.split(',')[1];\r\n const buffer = Buffer.from(base64, 'base64');\r\n const iconPath = path.join(servers[serverName].dir, 'server-icon.png');\r\n await fs.writeFile(iconPath, buffer);\r\n}\r\n\r\nasync function getIcon(serverName) {\r\n const iconPath = path.join(servers[serverName].dir, 'server-icon.png');\r\n try {\r\n const buffer = await fs.readFile(iconPath);\r\n return `data:image/png;base64,${buffer.toString('base64')}`;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nasync function getFiles(serverName, relativePath) {\r\n const basePath = servers[serverName].dir;\r\n const fullPath = path.join(basePath, relativePath);\r\n const files = await fs.readdir(fullPath, { withFileTypes: true });\r\n return files.map(file => ({\r\n name: file.name,\r\n isDir: file.isDirectory()\r\n }));\r\n}\r\n\r\nasync function renameFile(serverName, oldPath, newName) {\r\n const basePath = servers[serverName].dir;\r\n const oldFullPath = path.join(basePath, oldPath);\r\n const newFullPath = path.join(path.dirname(oldFullPath), newName);\r\n await fs.rename(oldFullPath, newFullPath);\r\n await loadServerFiles(serverName);\r\n}\r\n\r\nasync function deleteFile(serverName, filePath) {\r\n const fullPath = path.join(servers[serverName].dir, filePath);\r\n await fs.rm(fullPath, { recursive: true, force: true });\r\n await loadServerFiles(serverName);\r\n}\r\n\r\nmodule.exports = {\r\n uploadJar,\r\n uploadIcon,\r\n getIcon,\r\n getFiles,\r\n renameFile,\r\n deleteFile\r\n};",
- "Path": "/server/controllers/fileManager.js",
- "SizeKB": "2,46"
- },
- "/public/js/resourceMonitor.js": {
- "Content": "import { ws, currentServer } from './websocket.js';\r\n\r\nexport class ResourceMonitor {\r\n constructor() {\r\n this.initWebSocket();\r\n this.previousData = {};\r\n }\r\n\r\n initWebSocket() {\r\n const originalOnMessage = ws.onmessage;\r\n ws.onmessage = (event) => {\r\n if (originalOnMessage) originalOnMessage(event);\r\n const data = JSON.parse(event.data);\r\n if (data.type === 'resourceUpdate' && data.serverId === currentServer) {\r\n console.log(`Resource update dla ${data.serverId}: CPU ${data.cpu}%, RAM ${data.ram}MB 馃敟`);\r\n this.previousData[data.serverId] = { cpu: data.cpu, ram: data.ram };\r\n this.updateGauge('cpu', data.cpu);\r\n this.updateGauge('ram', data.ram);\r\n this.updateValueDisplay('cpu', data.cpu);\r\n this.updateValueDisplay('ram', data.ram);\r\n } else if (data.type === 'servers') {\r\n const server = data.servers[currentServer];\r\n if (server && !server.running) {\r\n console.log(`Serwer ${currentServer} wy艂膮czony, resetuj臋 gauges, kurwa! 馃惗`);\r\n this.updateGauge('cpu', 0);\r\n this.updateGauge('ram', 0);\r\n this.updateValueDisplay('cpu', 0);\r\n this.updateValueDisplay('ram', 0);\r\n }\r\n } else if (data.type === 'resourceUpdate') {\r\n console.log(`ResourceUpdate dla innego serverId (${data.serverId}), ignoruj臋, bo currentServer to ${currentServer}, kurwa! 馃槨`);\r\n }\r\n };\r\n }\r\n\r\n updateGauge(type, value) {\r\n const gauge = document.querySelector(`#${type}-gauge .gauge-needle`);\r\n const label = document.querySelector(`#${type}-gauge .gauge-label`);\r\n if (!gauge || !label) {\r\n console.log(`Kurwa, nie ma gauge albo label dla ${type}! 馃槨 Sprawd藕 HTML!`);\r\n return;\r\n }\r\n const maxValue = type === 'cpu' ? 100 : 16384;\r\n const clampedValue = Math.min(Math.max(value || 0, 0), maxValue);\r\n const angle = (clampedValue / maxValue) * 180 - 90;\r\n gauge.style.transform = `rotate(${angle}deg)`;\r\n label.textContent = type === 'cpu' ? 'CPU (%)' : 'RAM (MB)';\r\n console.log(`Zaktualizowano ${type}-gauge: ${clampedValue}/${maxValue}, k膮t: ${angle}掳, zajebi艣cie! 馃敟`);\r\n }\r\n\r\n updateValueDisplay(type, value) {\r\n const valueElement = document.querySelector(`#${type}-gauge .gauge-value`);\r\n if (!valueElement) {\r\n console.log(`Kurwa, brak gauge-value dla ${type}! 馃槨 Dodaj element w HTML!`);\r\n return;\r\n }\r\n const maxValue = type === 'cpu' ? 100 : 16384;\r\n const clampedValue = Math.min(Math.max(value || 0, 0), maxValue);\r\n valueElement.textContent = `${clampedValue}${type === 'cpu' ? '%' : 'MB'}`;\r\n console.log(`Wy艣wietlono ${type} warto艣膰: ${clampedValue}${type === 'cpu' ? '%' : 'MB'}`);\r\n }\r\n}",
- "Path": "/public/js/resourceMonitor.js",
- "SizeKB": "2,97"
- },
- "/logs/app_2025-03-16T14-48-18.664Z.log": {
- "Path": "/logs/app_2025-03-16T14-48-18.664Z.log",
- "SizeKB": "0,10"
- },
- "/public/css/styles.css": {
- "Content": "body {\r\n font-family: 'Segoe UI', Arial, sans-serif;\r\n background: #1e1e1e;\r\n color: #d4d4d4;\r\n margin: 0;\r\n padding: 0;\r\n height: 100vh;\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n}\r\n.header {\r\n background: #252526;\r\n padding: 10px 20px;\r\n box-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);\r\n}\r\n.header h1 {\r\n margin: 0;\r\n font-size: 20px;\r\n color: #ff4500;\r\n}\r\n.main {\r\n display: flex;\r\n flex: 1;\r\n}\r\n.sidebar {\r\n width: 250px;\r\n background: #2d2d2d;\r\n padding: 15px;\r\n box-shadow: 0 0 15px rgba(0, 0, 0, 0.3);\r\n overflow-y: auto;\r\n}\r\n.sidebar .add-server {\r\n display: flex;\r\n gap: 10px;\r\n margin-bottom: 15px;\r\n}\r\n.content {\r\n flex: 1;\r\n background: #2d2d2d;\r\n display: flex;\r\n flex-direction: column;\r\n}\r\n.server-header {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n padding: 10px;\r\n}\r\n.server-header img {\r\n width: 32px;\r\n height: 32px;\r\n margin-right: 10px;\r\n border-radius: 5px;\r\n}\r\n.controls {\r\n display: flex;\r\n gap: 10px;\r\n}\r\n.tabs {\r\n display: flex;\r\n background: #333;\r\n border-bottom: 2px solid #ff4500;\r\n flex-wrap: wrap;\r\n}\r\n.tab {\r\n padding: 10px 20px;\r\n cursor: pointer;\r\n transition: all 0.3s ease;\r\n display: flex;\r\n align-items: center;\r\n gap: 5px;\r\n}\r\n.tab:hover {\r\n background: #444;\r\n transform: translateY(-2px);\r\n}\r\n.tab.active {\r\n background: #ff4500;\r\n color: #fff;\r\n}\r\n.tab-content {\r\n flex: 1;\r\n padding: 15px;\r\n overflow-y: auto;\r\n display: none;\r\n}\r\n.tab-content.active {\r\n display: block;\r\n}\r\ninput, button, select, textarea {\r\n padding: 8px;\r\n margin: 5px 0;\r\n border: none;\r\n border-radius: 5px;\r\n background: #3c3c3c;\r\n color: #d4d4d4;\r\n transition: all 0.3s ease;\r\n}\r\nbutton {\r\n background: #ff4500;\r\n cursor: pointer;\r\n}\r\nbutton:hover {\r\n background: #ff6347;\r\n transform: scale(1.05);\r\n}\r\nbutton:disabled {\r\n background: #666;\r\n cursor: not-allowed;\r\n transform: none;\r\n}\r\nbutton.loading {\r\n background: #888;\r\n position: relative;\r\n}\r\nbutton.loading::after {\r\n content: '';\r\n position: absolute;\r\n width: 16px;\r\n height: 16px;\r\n border: 2px solid #fff;\r\n border-top: 2px solid transparent;\r\n border-radius: 50%;\r\n animation: spin 1s linear infinite;\r\n top: 50%;\r\n left: 50%;\r\n transform: translate(-50%, -50%);\r\n}\r\n.server-list .server-item {\r\n display: flex;\r\n align-items: center;\r\n background: #383838;\r\n padding: 10px;\r\n margin: 5px 0;\r\n border-radius: 5px;\r\n cursor: pointer;\r\n transition: background 0.3s ease, transform 0.2s ease;\r\n}\r\n.server-item:hover {\r\n background: #444;\r\n transform: translateX(5px);\r\n}\r\n.server-item.active {\r\n background: #ff4500;\r\n}\r\n.status-dot {\r\n width: 10px;\r\n height: 10px;\r\n border-radius: 50%;\r\n margin-right: 10px;\r\n transition: background 0.5s ease;\r\n}\r\n.status-dot.green {\r\n background: #00ff00;\r\n}\r\n.status-dot.red {\r\n background: #ff0000;\r\n}\r\n.status-dot.yellow {\r\n background: #ffff00;\r\n}\r\n.console {\r\n background: #1a1a1a;\r\n padding: 10px;\r\n border-radius: 5px;\r\n font-family: 'Consolas', monospace;\r\n white-space: pre-wrap;\r\n color: #d4d4d4;\r\n height: 400px;\r\n overflow-y: auto;\r\n overflow-x: auto;\r\n}\r\n.console::-webkit-scrollbar {\r\n width: 10px;\r\n height: 10px;\r\n}\r\n.console::-webkit-scrollbar-track {\r\n background: #2d2d2d;\r\n border-radius: 5px;\r\n}\r\n.console::-webkit-scrollbar-thumb {\r\n background: #ff4500;\r\n border-radius: 5px;\r\n}\r\n.console::-webkit-scrollbar-thumb:hover {\r\n background: #ff6347;\r\n}\r\n.console-input {\r\n display: flex;\r\n gap: 10px;\r\n margin-top: 10px;\r\n}\r\n.console-input input {\r\n flex: 1;\r\n background: #222;\r\n}\r\n.properties-editor, .java-panel {\r\n display: grid;\r\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\r\n gap: 15px;\r\n}\r\n.section {\r\n margin-bottom: 20px;\r\n}\r\n.section h3 {\r\n color: #ff4500;\r\n margin-bottom: 10px;\r\n}\r\n.property {\r\n display: flex;\r\n flex-direction: column;\r\n}\r\n.property label {\r\n display: flex;\r\n align-items: center;\r\n gap: 5px;\r\n font-size: 14px;\r\n}\r\n.property span {\r\n font-size: 12px;\r\n color: #a0a0a0;\r\n}\r\n.file-table {\r\n width: 100%;\r\n border-collapse: collapse;\r\n margin-top: 10px;\r\n}\r\n.file-table th, .file-table td {\r\n padding: 8px;\r\n text-align: left;\r\n border-bottom: 1px solid #444;\r\n}\r\n.file-table th {\r\n background: #383838;\r\n}\r\n.file-manager .files {\r\n height: 400px;\r\n overflow-y: auto;\r\n}\r\n.file-manager .files::-webkit-scrollbar {\r\n width: 10px;\r\n}\r\n.file-manager .files::-webkit-scrollbar-track {\r\n background: #2d2d2d;\r\n border-radius: 5px;\r\n}\r\n.file-manager .files::-webkit-scrollbar-thumb {\r\n background: #ff4500;\r\n border-radius: 5px;\r\n}\r\n.file-manager .files::-webkit-scrollbar-thumb:hover {\r\n background: #ff6347;\r\n}\r\n.file-item {\r\n padding: 5px;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n transition: background 0.3s ease;\r\n}\r\n.file-item:hover {\r\n background: #444;\r\n}\r\n.context-menu {\r\n position: absolute;\r\n background: #333;\r\n border: 1px solid #444;\r\n border-radius: 5px;\r\n padding: 5px 0;\r\n z-index: 1000;\r\n box-shadow: 0 4px 10px rgba(0, 0, 0, 0.5);\r\n animation: fadeIn 0.2s ease;\r\n}\r\n.context-menu div {\r\n padding: 5px 10px;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n gap: 5px;\r\n transition: background 0.2s ease;\r\n}\r\n.context-menu div:hover {\r\n background: #444;\r\n}\r\n.checkbox-container {\r\n display: flex;\r\n align-items: center;\r\n gap: 10px;\r\n}\r\n.checkbox-container input[type=\"checkbox\"] {\r\n appearance: none;\r\n width: 20px;\r\n height: 20px;\r\n background: #3c3c3c;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n position: relative;\r\n transition: background 0.3s ease;\r\n}\r\n.checkbox-container input[type=\"checkbox\"]:checked {\r\n background: #ff4500;\r\n}\r\n.checkbox-container input[type=\"checkbox\"]:checked::after {\r\n content: '鉁?;\r\n position: absolute;\r\n top: 50%;\r\n left: 50%;\r\n transform: translate(-50%, -50%);\r\n color: #fff;\r\n font-size: 14px;\r\n animation: checkPop 0.2s ease;\r\n}\r\n@keyframes fadeIn {\r\n from { opacity: 0; transform: scale(0.9); }\r\n to { opacity: 1; transform: scale(1); }\r\n}\r\n@keyframes checkPop {\r\n 0% { transform: translate(-50%, -50%) scale(0); }\r\n 50% { transform: translate(-50%, -50%) scale(1.2); }\r\n 100% { transform: translate(-50%, -50%) scale(1); }\r\n}\r\n@keyframes spin {\r\n 0% { transform: translate(-50%, -50%) rotate(0deg); }\r\n 100% { transform: translate(-50%, -50%) rotate(360deg); }\r\n}\r\n.mods-list {\r\n margin-top: 10px;\r\n}\r\n.mods-list div {\r\n display: flex;\r\n justify-content: space-between;\r\n padding: 5px;\r\n background: #383838;\r\n margin: 2px 0;\r\n border-radius: 5px;\r\n}\r\n.modal {\r\n display: none;\r\n position: fixed;\r\n top: 0;\r\n left: 0;\r\n width: 100%;\r\n height: 100%;\r\n background: rgba(0, 0, 0, 0.7);\r\n justify-content: center;\r\n align-items: center;\r\n z-index: 2000;\r\n}\r\n.modal-content {\r\n background: #333;\r\n padding: 20px;\r\n border-radius: 10px;\r\n width: 300px;\r\n text-align: center;\r\n box-shadow: 0 4px 15px rgba(0, 0, 0, 0.5);\r\n}\r\n.modal-content input {\r\n width: 80%;\r\n margin-bottom: 10px;\r\n}\r\n.modal-content button {\r\n margin: 5px;\r\n}\r\n.logs {\r\n background: #1a1a1a;\r\n padding: 10px;\r\n border-radius: 5px;\r\n font-family: 'Consolas', monospace;\r\n white-space: pre-wrap;\r\n color: #d4d4d4;\r\n height: 400px;\r\n overflow-y: auto;\r\n overflow-x: auto;\r\n}\r\n.logs::-webkit-scrollbar {\r\n width: 10px;\r\n height: 10px;\r\n}\r\n.logs::-webkit-scrollbar-track {\r\n background: #2d2d2d;\r\n border-radius: 5px;\r\n}\r\n.logs::-webkit-scrollbar-thumb {\r\n background: #ff4500;\r\n border-radius: 5px;\r\n}\r\n.logs::-webkit-scrollbar-thumb:hover {\r\n background: #ff6347;\r\n}\r\n.log-select {\r\n margin-bottom: 10px;\r\n width: 200px;\r\n}\r\n.log-line-info { color: #55ff55; }\r\n.log-line-warn { color: #ffff55; }\r\n.log-line-error { color: #ff5555; }\r\n\r\n/* Dodane style dla speedometr贸w i panelu zasob贸w */\r\n.resources {\r\n display: flex;\r\n justify-content: space-around;\r\n padding: 10px;\r\n background: #383838;\r\n border-radius: 5px;\r\n margin-top: 10px;\r\n}\r\n\r\n/* Mened偶er pobierania w zak艂adce Java */\r\n.version-selector {\r\n display: flex;\r\n align-items: center;\r\n gap: 10px;\r\n margin-bottom: 15px;\r\n}\r\n.version-selector select {\r\n flex: 1;\r\n max-height: 150px;\r\n overflow-y: auto;\r\n}\r\n.version-selector select::-webkit-scrollbar {\r\n width: 8px;\r\n}\r\n.version-selector select::-webkit-scrollbar-track {\r\n background: #2d2d2d;\r\n border-radius: 5px;\r\n}\r\n.version-selector select::-webkit-scrollbar-thumb {\r\n background: #ff4500;\r\n border-radius: 5px;\r\n}\r\n.version-selector select::-webkit-scrollbar-thumb:hover {\r\n background: #ff6347;\r\n}\r\n.download-progress {\r\n display: none;\r\n width: 100%;\r\n background: #383838;\r\n border-radius: 5px;\r\n padding: 5px;\r\n margin-top: 10px;\r\n}\r\n.progress-fill {\r\n height: 20px;\r\n background: #ff4500;\r\n border-radius: 3px;\r\n transition: width 0.3s ease;\r\n}\r\n.progress-text {\r\n font-size: 12px;\r\n color: #d4d4d4;\r\n margin-top: 5px;\r\n text-align: center;\r\n}",
- "Path": "/public/css/styles.css",
- "SizeKB": "9,26"
- },
- "/logs/minecraft_2025-03-16T15-08-18.725Z.log": {
- "Path": "/logs/minecraft_2025-03-16T15-08-18.725Z.log",
- "SizeKB": "0,40"
- },
- "/logs/error_2025-03-16T15-00-13.680Z.log": {
- "Path": "/logs/error_2025-03-16T15-00-13.680Z.log",
- "SizeKB": "0,42"
- },
- "/public/css/light-theme.css": {
- "Content": null,
- "Path": "/public/css/light-theme.css",
- "SizeKB": "0,00"
- },
- "/logs/minecraft_2025-04-16T15-46-59.644Z.log": {
- "Path": "/logs/minecraft_2025-04-16T15-46-59.644Z.log",
- "SizeKB": "2,85"
- },
- "/server/controllers/wsHandler.js": {
- "Content": "const { log } = require('../utils/logger');\r\nconst { servers, startServer, stopServer, restartServer, killServer, saveInstance, addServer, deleteServer } = require('./serverManager');\r\nconst { uploadJar, uploadIcon, getIcon, getFiles, renameFile, deleteFile } = require('./fileManager');\r\nconst { getJavaVersions, scanJavaVersions } = require('./javaManager');\r\nconst fs = require('fs').promises;\r\nconst path = require('path');\r\nconst https = require('https');\r\n\r\n// Prosty debounce dla request贸w\r\nconst debounce = (func, wait) => {\r\n let timeout;\r\n return (...args) => {\r\n clearTimeout(timeout);\r\n timeout = setTimeout(() => func(...args), wait);\r\n };\r\n};\r\n\r\nfunction normalizePath(p) {\r\n return p.replace(/\\\\\\\\/g, '/').toLowerCase();\r\n}\r\n\r\nasync function fetchMinecraftVersions() {\r\n console.log('fetchMinecraftVersions, pobieramy wersje...');\r\n return new Promise((resolve, reject) => {\r\n https.get('https://launchermeta.mojang.com/mc/game/version_manifest_v2.json', (res) => {\r\n let data = '';\r\n res.on('data', (chunk) => data += chunk);\r\n res.on('end', () => {\r\n try {\r\n const manifest = JSON.parse(data);\r\n console.log('Pobrano manifest wersji MC, zajebi艣cie! 馃槑', manifest.versions.map(v => v.id));\r\n resolve(manifest.versions);\r\n } catch (e) {\r\n console.log('Kurwa, b艂膮d parsowania manifestu!', e);\r\n reject(e);\r\n }\r\n });\r\n }).on('error', (e) => {\r\n console.log('Kurwa, b艂膮d pobierania wersji MC!', e);\r\n reject(e);\r\n });\r\n });\r\n}\r\n\r\nasync function downloadJar(serverName, version, ws) {\r\n console.log(`downloadJar dla ${serverName}, wersja: ${version}`);\r\n const versions = await fetchMinecraftVersions();\r\n const selectedVersion = versions.find(v => v.id === version);\r\n if (!selectedVersion) {\r\n log('error', 'error', `[DOWNLOAD_JAR_ERROR] Wersja ${version} nie znaleziona`);\r\n console.log(`Kurwa, wersja ${version} nie istnieje! 馃槨`);\r\n return;\r\n }\r\n\r\n const versionDetails = await new Promise((resolve, reject) => {\r\n https.get(selectedVersion.url, (res) => {\r\n let data = '';\r\n res.on('data', (chunk) => data += chunk);\r\n res.on('end', () => {\r\n try {\r\n const details = JSON.parse(data);\r\n console.log(`Pobrano szczeg贸艂y wersji ${version}:`, details.downloads.server.url);\r\n resolve(details);\r\n } catch (e) {\r\n console.log('Kurwa, b艂膮d parsowania szczeg贸艂贸w wersji!', e);\r\n reject(e);\r\n }\r\n });\r\n }).on('error', (e) => {\r\n console.log('Kurwa, b艂膮d pobierania szczeg贸艂贸w wersji!', e);\r\n reject(e);\r\n });\r\n });\r\n\r\n const jarUrl = versionDetails.downloads.server.url;\r\n const serverDir = path.join(__dirname, '../servers', serverName);\r\n const jarPath = path.join(serverDir, `server-${version}.jar`);\r\n const file = await fs.open(jarPath, 'w');\r\n let downloadedBytes = 0;\r\n let totalBytes = 0;\r\n let startTime = Date.now();\r\n\r\n const req = https.get(jarUrl, (res) => {\r\n totalBytes = parseInt(res.headers['content-length'], 10);\r\n res.pipe(file.createWriteStream());\r\n\r\n res.on('data', (chunk) => {\r\n downloadedBytes += chunk.length;\r\n const progress = Math.round((downloadedBytes / totalBytes) * 100);\r\n const downloadedMB = (downloadedBytes / 1024 / 1024).toFixed(2);\r\n const totalMB = (totalBytes / 1024 / 1024).toFixed(2);\r\n const elapsedTime = (Date.now() - startTime) / 1000;\r\n const speed = (downloadedMB / elapsedTime).toFixed(2);\r\n\r\n ws.send(JSON.stringify({\r\n type: 'downloadProgress',\r\n serverName,\r\n progress,\r\n downloadedMB,\r\n totalMB,\r\n speed\r\n }));\r\n });\r\n\r\n res.on('end', async () => {\r\n await file.close();\r\n ws.send(JSON.stringify({\r\n type: 'downloadComplete',\r\n serverName,\r\n filename: `server-${version}.jar`\r\n }));\r\n log('server', 'info', `[DOWNLOAD_JAR] Pobrano server-${version}.jar dla ${serverName}`);\r\n console.log(`Zapisano server-${version}.jar dla ${serverName}, zajebi艣cie! 馃敟`);\r\n });\r\n });\r\n\r\n req.on('error', async (e) => {\r\n log('error', 'error', `[DOWNLOAD_JAR_ERROR] B艂膮d pobierania ${version}`, e);\r\n console.log('Kurwa, b艂膮d pobierania JAR!', e);\r\n await file.close();\r\n });\r\n}\r\n\r\nfunction handleWebSocket(ws) {\r\n ws.on('message', async (message) => {\r\n const data = JSON.parse(message);\r\n log('server', 'info', `[CLIENT_ACTION] 呕膮danie klienta: ${data.type}`, data);\r\n console.log(`Odebrano: ${data.type}`, data);\r\n\r\n switch (data.type) {\r\n case 'getServers':\r\n console.log('Wysy艂am serwery, kurwa:', servers);\r\n ws.send(JSON.stringify({ type: 'servers', servers }));\r\n console.log('Wys艂ano serwery, zajebi艣cie! 馃敟');\r\n const currentJavaVersions = await scanJavaVersions();\r\n console.log('Wysy艂am Javy:', currentJavaVersions);\r\n ws.send(JSON.stringify({ type: 'javaVersions', versions: currentJavaVersions }));\r\n break;\r\n\r\n case 'addServer':\r\n await addServer(data.name);\r\n break;\r\n\r\n case 'deleteServer':\r\n await deleteServer(data.serverName);\r\n break;\r\n\r\n case 'startServer':\r\n await startServer(data.serverName, ws);\r\n break;\r\n\r\n case 'stopServer':\r\n stopServer(data.serverName);\r\n break;\r\n\r\n case 'restartServer':\r\n await restartServer(data.serverName, ws);\r\n break;\r\n\r\n case 'killServer':\r\n killServer(data.serverName);\r\n await saveInstance(data.serverName);\r\n break;\r\n\r\n case 'uploadJar':\r\n debounce(async () => {\r\n await uploadJar(data.serverName, data.data, data.filename);\r\n await saveInstance(data.serverName);\r\n require('./serverManager').broadcastServers();\r\n log('server', 'info', `[JAR_UPLOAD_BROADCAST] Rozes艂ano aktualizacj臋 po uploadzie JAR dla ${data.serverName}, zajebi艣cie! 馃敟`);\r\n }, 500)();\r\n break;\r\n\r\n case 'uploadIcon':\r\n await uploadIcon(data.serverName, data.data);\r\n ws.send(JSON.stringify({ type: 'icon', serverName: data.serverName, data: data.data }));\r\n break;\r\n\r\n case 'getIcon':\r\n const iconData = await getIcon(data.serverName);\r\n if (iconData) ws.send(JSON.stringify({ type: 'icon', serverName: data.serverName, data: iconData }));\r\n break;\r\n\r\n case 'getFiles':\r\n const files = await getFiles(data.serverName, data.path);\r\n ws.send(JSON.stringify({ type: 'fileList', path: data.path, files }));\r\n break;\r\n\r\n case 'renameFile':\r\n await renameFile(data.serverName, data.path, data.newName);\r\n break;\r\n\r\n case 'deleteFile':\r\n await deleteFile(data.serverName, data.path);\r\n break;\r\n\r\n case 'getLog':\r\n const logsDir = path.join(__dirname, '../servers', data.serverName, 'logs');\r\n const logPath = path.join(logsDir, data.logFile);\r\n try {\r\n await fs.mkdir(logsDir, { recursive: true });\r\n const logContent = await fs.readFile(logPath, 'utf8');\r\n ws.send(JSON.stringify({ type: 'logContent', serverName: data.serverName, logContent }));\r\n } catch (e) {\r\n log('error', 'error', `[LOG_ERROR] Nie mo偶na wczyta膰 logu ${data.logFile}: ${e}`);\r\n ws.send(JSON.stringify({ type: 'logContent', serverName: data.serverName, logContent: 'Brak log贸w, kurwa! Serwer jeszcze nie uruchomiony? 馃槢' }));\r\n }\r\n break;\r\n\r\n case 'setJava':\r\n debounce(async () => {\r\n if (!servers[data.serverName]) {\r\n log('error', 'error', `[SET_JAVA_ERROR] Serwer ${data.serverName} nie istnieje, kurwa! 馃槨`);\r\n return;\r\n }\r\n if (servers[data.serverName].running) {\r\n log('warn', 'warn', `[SET_JAVA_WARN] Serwer ${data.serverName} dzia艂a, nie zmieniam Javy! 馃槢`);\r\n return;\r\n }\r\n\r\n const javaVersions = getJavaVersions();\r\n log('debug', 'info', `[SET_JAVA_DEBUG] Dost臋pne javaVersions: ${JSON.stringify(javaVersions)}`);\r\n log('debug', 'info', `[SET_JAVA_DEBUG] Otrzymana wersja: ${data.version}`);\r\n\r\n const normalizedRequestedPath = normalizePath(data.version);\r\n const selectedJava = javaVersions.find(j => normalizePath(j.path) === normalizedRequestedPath);\r\n\r\n if (!selectedJava) {\r\n log('error', 'error', `[SET_JAVA_ERROR] Wersja Javy ${data.version} nie znaleziona, kurwa ma膰! 馃槨`);\r\n return;\r\n }\r\n\r\n servers[data.serverName].javaPath = selectedJava.path;\r\n servers[data.serverName].java = selectedJava.version;\r\n await saveInstance(data.serverName);\r\n log('server', 'info', `[SET_JAVA] Ustawiono Jav臋 ${selectedJava.version} (${selectedJava.path}) dla ${data.serverName}, w chuj git! 馃敟`);\r\n require('./serverManager').broadcastServers();\r\n }, 500)();\r\n break;\r\n\r\n case 'setRam':\r\n debounce(async () => {\r\n if (servers[data.serverName] && !servers[data.serverName].running) {\r\n const newRam = parseInt(data.ram, 10);\r\n if (isNaN(newRam) || newRam < 1) {\r\n log('error', 'error', `[SET_RAM_ERROR] Nieprawid艂owy RAM: ${data.ram} dla ${data.serverName}`);\r\n return;\r\n }\r\n if (servers[data.serverName].ram !== newRam) {\r\n servers[data.serverName].ram = newRam;\r\n await saveInstance(data.serverName);\r\n log('server', 'info', `[SET_RAM] Ustawiono RAM ${newRam}G dla ${data.serverName}`);\r\n }\r\n require('./serverManager').broadcastServers();\r\n } else {\r\n log('error', 'error', `[SET_RAM_ERROR] Serwer ${data.serverName} dzia艂a lub nie istnieje`);\r\n }\r\n }, 500)();\r\n break;\r\n\r\n case 'setJavaParams':\r\n debounce(async () => {\r\n if (servers[data.serverName] && !servers[data.serverName].running) {\r\n if (servers[data.serverName].javaParams !== data.params) {\r\n servers[data.serverName].javaParams = data.params;\r\n await saveInstance(data.serverName);\r\n log('server', 'info', `[SET_PARAMS] Ustawiono parametry Javy ${data.params} dla ${data.serverName}`);\r\n }\r\n require('./serverManager').broadcastServers();\r\n } else {\r\n log('error', 'error', `[SET_PARAMS_ERROR] Serwer ${data.serverName} dzia艂a lub nie istnieje`);\r\n }\r\n }, 500)();\r\n break;\r\n\r\n case 'setMcVersion':\r\n debounce(async () => {\r\n if (servers[data.serverName]) {\r\n if (servers[data.serverName].mcVersion !== data.version) {\r\n servers[data.serverName].mcVersion = data.version;\r\n await saveInstance(data.serverName);\r\n log('server', 'info', `[SET_MC_VERSION] Ustawiono wersj臋 MC ${data.version} dla ${data.serverName}`);\r\n }\r\n require('./serverManager').broadcastServers();\r\n } else {\r\n log('error', 'error', `[SET_MC_VERSION_ERROR] Serwer ${data.serverName} nie istnieje`);\r\n }\r\n }, 500)();\r\n break;\r\n\r\n case 'sendCommand':\r\n if (servers[data.serverName] && servers[data.serverName].running) {\r\n const server = servers[data.serverName];\r\n if (server.process) {\r\n server.process.stdin.write(`${data.command}\\n`);\r\n log('server', 'info', `[COMMAND] Wys艂ano komend臋 do ${data.serverName}: ${data.command}`);\r\n ws.send(JSON.stringify({ type: 'commandResponse', serverName: data.serverName, message: `Komenda \"${data.command}\" wys艂ana, kurwa git!` }));\r\n } else {\r\n log('error', 'error', `[COMMAND_ERROR] Brak procesu dla ${data.serverName}`);\r\n ws.send(JSON.stringify({ type: 'error', serverName: data.serverName, message: 'Serwer nie ma aktywnego procesu, kurwa!' }));\r\n }\r\n } else {\r\n log('error', 'error', `[COMMAND_ERROR] Serwer ${data.serverName} nie dzia艂a lub nie istnieje`);\r\n ws.send(JSON.stringify({ type: 'error', serverName: data.serverName, message: 'Serwer nie dzia艂a albo nie istnieje, ziom!' }));\r\n }\r\n break;\r\n\r\n case 'getVersions':\r\n console.log(`getVersions dla ${data.serverName}, pobieramy...`);\r\n const versions = await fetchMinecraftVersions();\r\n const serverDir = path.join(__dirname, '../servers', data.serverName);\r\n let localFiles = [];\r\n try {\r\n const files = await fs.readdir(serverDir);\r\n localFiles = files.filter(f => f.startsWith('server-') && f.endsWith('.jar')).map(f => f.replace('server-', '').replace('.jar', ''));\r\n console.log(`Lokalne JAR-y dla ${data.serverName}:`, localFiles);\r\n } catch (e) {\r\n log('error', 'error', `[GET_VERSIONS_ERROR] B艂膮d odczytu folderu serwera ${data.serverName}`, e);\r\n console.log(`Kurwa, b艂膮d odczytu folderu ${serverDir}!`, e);\r\n }\r\n ws.send(JSON.stringify({ type: 'versionsList', serverName: data.serverName, versions, localFiles }));\r\n console.log(`Wys艂ano versionsList dla ${data.serverName}, wersje:`, versions.map(v => v.id));\r\n break;\r\n\r\n case 'downloadJar':\r\n await downloadJar(data.serverName, data.version, ws);\r\n break;\r\n\r\n case 'setJar':\r\n if (servers[data.serverName] && !servers[data.serverName].running) {\r\n servers[data.serverName].jar = data.jar;\r\n await saveInstance(data.serverName);\r\n log('server', 'info', `[SET_JAR] Ustawiono JAR ${data.jar} dla ${data.serverName}`);\r\n require('./serverManager').broadcastServers();\r\n } else {\r\n log('error', 'error', `[SET_JAR_ERROR] Serwer ${data.serverName} dzia艂a lub nie istnieje`);\r\n }\r\n break;\r\n\r\n default:\r\n log('server', 'warn', `[CLIENT_ACTION] Nieznane 偶膮danie klienta: ${data.type}`);\r\n console.log(`Nieznane 偶膮danie: ${data.type}`);\r\n }\r\n });\r\n}\r\n\r\nmodule.exports = { handleWebSocket };",
- "Path": "/server/controllers/wsHandler.js",
- "SizeKB": "16,10"
- },
- "/logs/app_2025-04-16T15-33-05.987Z.log": {
- "Path": "/logs/app_2025-04-16T15-33-05.987Z.log",
- "SizeKB": "0,10"
- },
- "/public/js/settings.js": {
- "Content": "import { sendMessage, servers, currentServer } from './websocket.js';\r\nimport { setServerCallbacks } from './server.js';\r\n\r\nconst SERVER_PROPERTIES_DB = {\r\n 'motd': { label: 'MOTD', icon: '馃摐', desc: 'Wiadomo艣膰 dnia wy艣wietlana w menu gry', type: 'text' },\r\n 'difficulty': { label: 'Trudno艣膰', icon: '鈿旓笍', desc: 'Poziom trudno艣ci gry', type: 'select', options: ['peaceful', 'easy', 'normal', 'hard'] },\r\n 'gamemode': { label: 'Tryb gry', icon: '馃幃', desc: 'Domy艣lny tryb gry dla nowych graczy', type: 'select', options: ['survival', 'creative', 'adventure', 'spectator'] },\r\n 'max-players': { label: 'Max graczy', icon: '馃懃', desc: 'Maksymalna liczba graczy na serwerze', type: 'number', min: 1 },\r\n 'pvp': { label: 'PvP', icon: '馃ず', desc: 'W艂膮cza/wy艂膮cza walk臋 mi臋dzy graczami', type: 'checkbox' },\r\n 'online-mode': { label: 'Online Mode', icon: '馃寪', desc: 'Weryfikacja licencji przez Mojang', type: 'checkbox' },\r\n 'level-type': { label: 'Typ 艣wiata', icon: '馃實', desc: 'Rodzaj generowanego 艣wiata', type: 'select', options: ['DEFAULT', 'FLAT', 'LARGEBIOMES', 'AMPLIFIED', 'CUSTOMIZED'] },\r\n 'spawn-protection': { label: 'Ochrona spawnu', icon: '馃洝锔?, desc: 'Promie艅 ochrony spawnu w blokach', type: 'number', min: 0 },\r\n 'hardcore': { label: 'Hardcore', icon: '馃拃', desc: 'W艂膮cza tryb hardcore', type: 'checkbox' },\r\n 'allow-flight': { label: 'Latanie', icon: '鉁堬笍', desc: 'Pozwala na latanie w trybie survival', type: 'checkbox' },\r\n 'generate-structures': { label: 'Struktury', icon: '馃彴', desc: 'Generuje wioski, 艣wi膮tynie itp.', type: 'checkbox' },\r\n 'level-seed': { label: 'Seed 艣wiata', icon: '馃尡', desc: 'Seed do generowania 艣wiata', type: 'text' },\r\n 'enforce-whitelist': { label: 'Wymagaj bia艂ej listy', icon: '馃搵', desc: 'Blokuje graczy spoza bia艂ej listy', type: 'checkbox' },\r\n 'resource-pack': { label: 'Paczka zasob贸w', icon: '馃帹', desc: 'URL do paczki zasob贸w', type: 'text' },\r\n 'resource-pack-sha1': { label: 'SHA1 paczki', icon: '馃攽', desc: 'Hash SHA1 paczki zasob贸w', type: 'text' },\r\n 'server-port': { label: 'Port serwera', icon: '馃攲', desc: 'Port, na kt贸rym dzia艂a serwer', type: 'number', min: 1, max: 65535 },\r\n 'white-list': { label: 'Bia艂a lista', icon: '鉁?, desc: 'W艂膮cza bia艂膮 list臋', type: 'checkbox' }\r\n};\r\n\r\nexport function initSettings() {\r\n document.getElementById('serverNameEdit').addEventListener('change', (e) => renameServer(e.target.value));\r\n document.getElementById('iconUpload').addEventListener('change', uploadIcon);\r\n document.getElementById('submitModalBtn').addEventListener('click', submitModal);\r\n document.getElementById('closeModalBtn').addEventListener('click', closeModal);\r\n\r\n setServerCallbacks({\r\n properties: updateProperties,\r\n players: updatePlayersManagement\r\n });\r\n}\r\n\r\nfunction updateProperties(props) {\r\n const container = document.getElementById('properties');\r\n container.innerHTML = '';\r\n const sections = {\r\n 'Og贸lne': [],\r\n 'Rozgrywka': [],\r\n '艢wiat': [],\r\n 'Sie膰': []\r\n };\r\n\r\n Object.keys(SERVER_PROPERTIES_DB).forEach(key => {\r\n if (props.hasOwnProperty(key)) {\r\n const field = SERVER_PROPERTIES_DB[key];\r\n const div = document.createElement('div');\r\n div.className = 'property';\r\n div.innerHTML = `<label>${field.icon} ${field.label}: `;\r\n if (field.type === 'select') {\r\n const select = document.createElement('select');\r\n field.options.forEach(opt => {\r\n const option = document.createElement('option');\r\n option.value = opt;\r\n option.textContent = opt;\r\n if (opt === props[key]) option.selected = true;\r\n select.appendChild(option);\r\n });\r\n select.onchange = () => editProperties();\r\n select.id = key;\r\n div.appendChild(select);\r\n } else if (field.type === 'checkbox') {\r\n const container = document.createElement('div');\r\n container.className = 'checkbox-container';\r\n const input = document.createElement('input');\r\n input.type = 'checkbox';\r\n input.checked = props[key] === 'true';\r\n input.onchange = () => editProperties();\r\n input.id = key;\r\n container.appendChild(input);\r\n container.appendChild(document.createTextNode(' '));\r\n div.appendChild(container);\r\n } else {\r\n const input = document.createElement('input');\r\n input.type = field.type || 'text';\r\n if (field.min) input.min = field.min;\r\n if (field.max) input.max = field.max;\r\n input.value = props[key];\r\n input.onchange = () => editProperties();\r\n input.id = key;\r\n div.appendChild(input);\r\n }\r\n div.innerHTML += `</label><span>${field.desc}</span>`;\r\n if (['motd', 'max-players', 'online-mode'].includes(key)) sections['Og贸lne'].push(div);\r\n else if (['difficulty', 'gamemode', 'pvp', 'hardcore', 'allow-flight'].includes(key)) sections['Rozgrywka'].push(div);\r\n else if (['level-type', 'spawn-protection', 'generate-structures', 'level-seed'].includes(key)) sections['艢wiat'].push(div);\r\n else if (['server-port', 'white-list', 'enforce-whitelist', 'resource-pack', 'resource-pack-sha1'].includes(key)) sections['Sie膰'].push(div);\r\n }\r\n });\r\n\r\n Object.keys(sections).forEach(section => {\r\n if (sections[section].length > 0) {\r\n const secDiv = document.createElement('div');\r\n secDiv.className = 'section';\r\n secDiv.innerHTML = `<h3>${section}</h3>`;\r\n sections[section].forEach(div => secDiv.appendChild(div));\r\n container.appendChild(secDiv);\r\n }\r\n });\r\n}\r\n\r\nfunction editProperties() {\r\n if (!currentServer) return;\r\n const props = {};\r\n Object.keys(SERVER_PROPERTIES_DB).forEach(id => {\r\n const el = document.getElementById(id);\r\n if (el) props[id] = el.type === 'checkbox' ? String(el.checked) : el.value;\r\n });\r\n sendMessage({ type: 'editProperties', serverName: currentServer, properties: props });\r\n}\r\n\r\nfunction updatePlayersManagement(containerId, file, headers, key) {\r\n const container = document.getElementById(containerId);\r\n container.innerHTML = '';\r\n const table = document.createElement('table');\r\n table.className = 'file-table';\r\n table.innerHTML = `<thead><tr>${headers.map(h => `<th>${h}</th>`).join('')}</tr></thead><tbody></tbody>`;\r\n const tbody = table.querySelector('tbody');\r\n const data = servers[currentServer].files[file] ? JSON.parse(servers[currentServer].files[file]) : [];\r\n data.forEach((entry, i) => {\r\n const tr = document.createElement('tr');\r\n tr.innerHTML = `\r\n <td>${entry[key]}</td>\r\n ${file === 'ops.json' ? `<td>${entry.level || 4}</td>` : headers.length > 2 ? `<td>${entry.reason || 'Brak'}</td>` : ''}\r\n <td><button onclick=\"removeEntry('${file}', ${i})\">馃棏锔?/button></td>\r\n `;\r\n tbody.appendChild(tr);\r\n });\r\n const addBtn = document.createElement('button');\r\n addBtn.textContent = 'Dodaj';\r\n addBtn.addEventListener('click', () => showModal(file, key));\r\n container.appendChild(table);\r\n container.appendChild(addBtn);\r\n}\r\n\r\nlet modalCallback = null;\r\n\r\nfunction showModal(file, key) {\r\n const modal = document.getElementById('entryModal');\r\n const title = document.getElementById('modalTitle');\r\n const input = document.getElementById('modalInput');\r\n title.textContent = `Dodaj ${key === 'ip' ? 'IP' : 'nick'}`;\r\n input.value = '';\r\n modal.style.display = 'flex';\r\n modalCallback = (value) => {\r\n if (!value) return;\r\n const data = servers[currentServer].files[file] ? JSON.parse(servers[currentServer].files[file]) : [];\r\n const entry = key === 'ip' ? { ip: value, reason: 'Manual', created: new Date().toISOString(), expires: 'forever', source: 'Panel' } :\r\n file === 'ops.json' ? { uuid: 'manual-' + Date.now(), name: value, level: 4 } :\r\n file === 'whitelist.json' ? { uuid: 'manual-' + Date.now(), name: value } :\r\n { uuid: 'manual-' + Date.now(), name: value, reason: 'Manual', created: new Date().toISOString(), expires: 'forever', source: 'Panel' };\r\n data.push(entry);\r\n sendMessage({ type: 'editFile', serverName: currentServer, file, content: JSON.stringify(data, null, 2) });\r\n };\r\n}\r\n\r\nfunction submitModal() {\r\n const input = document.getElementById('modalInput').value;\r\n if (modalCallback) modalCallback(input);\r\n closeModal();\r\n}\r\n\r\nfunction closeModal() {\r\n document.getElementById('entryModal').style.display = 'none';\r\n modalCallback = null;\r\n}\r\n\r\nfunction removeEntry(file, index) {\r\n const data = JSON.parse(servers[currentServer].files[file]);\r\n data.splice(index, 1);\r\n sendMessage({ type: 'editFile', serverName: currentServer, file, content: JSON.stringify(data, null, 2) });\r\n}\r\n\r\nfunction renameServer(newName) {\r\n if (newName && newName !== currentServer && !servers[currentServer].running) {\r\n sendMessage({ type: 'renameServer', serverName: currentServer, newName });\r\n setCurrentServer(newName); // Aktualizujemy currentServer po zmianie nazwy\r\n } else if (servers[currentServer].running) {\r\n alert('Kurwa, zatrzymaj serwer, zanim zmienisz nazw臋! 馃槢');\r\n }\r\n}\r\n\r\nfunction uploadIcon() {\r\n const file = document.getElementById('iconUpload').files[0];\r\n if (file && currentServer && !servers[currentServer].running) {\r\n const reader = new FileReader();\r\n reader.onload = () => sendMessage({ type: 'uploadIcon', serverName: currentServer, data: reader.result });\r\n reader.readAsDataURL(file);\r\n } else if (servers[currentServer].running) {\r\n alert('Zatrzymaj serwer, zanim wrzucisz now膮 ikon臋, ziom! 馃槣');\r\n }\r\n}",
- "Path": "/public/js/settings.js",
- "SizeKB": "10,05"
- },
- "/logs/server_2025-03-16T14-50-54.242Z.log": {
- "Path": "/logs/server_2025-03-16T14-50-54.242Z.log",
- "SizeKB": "3,61"
- },
- "/logs/debug_2025-03-16T15-00-13.680Z.log": {
- "Path": "/logs/debug_2025-03-16T15-00-13.680Z.log",
- "SizeKB": "11,46"
- },
- "/logs/app_2025-04-16T15-08-42.487Z.log": {
- "Path": "/logs/app_2025-04-16T15-08-42.487Z.log",
- "SizeKB": "0,10"
- },
- "/logs/minecraft_2025-04-16T15-38-13.014Z.log": {
- "Path": "/logs/minecraft_2025-04-16T15-38-13.014Z.log",
- "SizeKB": "0,08"
- },
- "/public/img/icon_32.png": {
- "Path": "/public/img/icon_32.png",
- "SizeKB": "1,12"
- },
- "/logs/app_2025-04-16T15-48-07.953Z.log": {
- "Path": "/logs/app_2025-04-16T15-48-07.953Z.log",
- "SizeKB": "0,10"
- },
- "/logs/server_2025-03-16T14-48-18.664Z.log": {
- "Path": "/logs/server_2025-03-16T14-48-18.664Z.log",
- "SizeKB": "7,98"
- },
- "/public/css/dark-theme.css": {
- "Content": null,
- "Path": "/public/css/dark-theme.css",
- "SizeKB": "0,00"
- },
- "/logs/debug_2025-04-16T15-46-59.644Z.log": {
- "Path": "/logs/debug_2025-04-16T15-46-59.644Z.log",
- "SizeKB": "17,58"
- },
- "/logs/app_2025-03-16T14-07-15.354Z.log": {
- "Path": "/logs/app_2025-03-16T14-07-15.354Z.log",
- "SizeKB": "0,10"
- },
- "/server/java-config.json": {
- "Content": "[\n {\n \"version\": \"java-21.0.4\",\n \"path\": \"java\"\n },\n {\n \"version\": \"azul_zulu_jre21.0.5\",\n \"path\": \"C:\\\\Users\\\\Admin\\\\Desktop\\\\minecraft-server-manager\\\\server\\\\javas\\\\azul_zulu_jre21.0.5\\\\bin\\\\java.exe\"\n },\n {\n \"version\": \"graalvm-jdk-21.0.6+8.1\",\n \"path\": \"C:\\\\Users\\\\Admin\\\\Desktop\\\\minecraft-server-manager\\\\server\\\\javas\\\\graalvm-jdk-21.0.6+8.1\\\\bin\\\\java.exe\"\n },\n {\n \"version\": \"graalvm-jdk-23.0.2+7.1\",\n \"path\": \"C:\\\\Users\\\\Admin\\\\Desktop\\\\minecraft-server-manager\\\\server\\\\javas\\\\graalvm-jdk-23.0.2+7.1\\\\bin\\\\java.exe\"\n },\n {\n \"version\": \"java-runtime-beta\",\n \"path\": \"C:\\\\Users\\\\Admin\\\\Desktop\\\\minecraft-server-manager\\\\server\\\\javas\\\\java-runtime-beta\\\\bin\\\\java.exe\"\n },\n {\n \"version\": \"java-runtime-delta\",\n \"path\": \"C:\\\\Users\\\\Admin\\\\Desktop\\\\minecraft-server-manager\\\\server\\\\javas\\\\java-runtime-delta\\\\bin\\\\java.exe\"\n },\n {\n \"version\": \"java-runtime-gamma\",\n \"path\": \"C:\\\\Users\\\\Admin\\\\Desktop\\\\minecraft-server-manager\\\\server\\\\javas\\\\java-runtime-gamma\\\\bin\\\\java.exe\"\n },\n {\n \"version\": \"jdk-16\",\n \"path\": \"C:\\\\Users\\\\Admin\\\\Desktop\\\\minecraft-server-manager\\\\server\\\\javas\\\\jdk-16\\\\bin\\\\java.exe\"\n },\n {\n \"version\": \"jdk-21\",\n \"path\": \"C:\\\\Users\\\\Admin\\\\Desktop\\\\minecraft-server-manager\\\\server\\\\javas\\\\jdk-21\\\\bin\\\\java.exe\"\n },\n {\n \"version\": \"jre-legacy\",\n \"path\": \"C:\\\\Users\\\\Admin\\\\Desktop\\\\minecraft-server-manager\\\\server\\\\javas\\\\jre-legacy\\\\bin\\\\java.exe\"\n }\n]",
- "Path": "/server/java-config.json",
- "SizeKB": "1,44"
- },
- "/logs/error_2025-03-16T15-11-15.055Z.log": {
- "Path": "/logs/error_2025-03-16T15-11-15.055Z.log",
- "SizeKB": "0,09"
- },
- "/logs/debug_2025-03-16T15-08-18.725Z.log": {
- "Path": "/logs/debug_2025-03-16T15-08-18.725Z.log",
- "SizeKB": "8,49"
- },
- "/logs/server_2025-03-16T19-09-40.484Z.log": {
- "Path": "/logs/server_2025-03-16T19-09-40.484Z.log",
- "SizeKB": "5,12"
- },
- "/logs/debug_2025-04-16T15-33-05.987Z.log": {
- "Path": "/logs/debug_2025-04-16T15-33-05.987Z.log",
- "SizeKB": "17,48"
- },
- "/minecraft-server-manager.7z": {
- "Path": "/minecraft-server-manager.7z",
- "SizeKB": "2聽593聽982,51"
- },
- "/logs/server_2025-03-16T15-17-44.816Z.log": {
- "Path": "/logs/server_2025-03-16T15-17-44.816Z.log",
- "SizeKB": "7,57"
- }
- }
Add Comment
Please, Sign In to add comment