diff --git a/src/configmenu.js b/src/configmenu.js index 140b076..804fab0 100644 --- a/src/configmenu.js +++ b/src/configmenu.js @@ -3,8 +3,33 @@ import chalk from 'chalk'; import { showErrorMessage, showInfoMessage } from './utils/messages.js'; import { isDir, showPathSelector } from './utils/pathSelector.js'; import { saveConfig } from './services/config.js'; +import { showNumberSelector } from './utils/numberSelector.js'; import fs from 'fs-extra'; +function bytesAmountToString(numBytes) { + const units = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; + + var value = numBytes; + var index = 0; + while (value > 1024) { + index = index + 1; + value = value / 1024; + } + + if (index == 0) return `${numBytes} Bytes`; + return `${numBytes} Bytes (${value} ${units[index]})`; +} + +async function showStorageQuotaSelector(config) { + console.log(showInfoMessage('You can use: "GB" or "gb", etc.')); + const result = await showNumberSelector(config.storageQuota, "Storage quota", true); + if (result < (100 * 1024 * 1024)) { + console.log(showErrorMessage("Storage quote should be >= 100mb.")); + return config.storageQuota; + } + return result; +} + export async function showConfigMenu(config) { var newDataDir = config.dataDir; try { @@ -18,7 +43,7 @@ export async function showConfigMenu(config) { choices: [ `1. Data path = "${newDataDir}"`, `2. Logs path = "${config.logsDir}"`, - '3. Storage quota = TODO', + `3. Storage quota = ${bytesAmountToString(config.storageQuota)}`, '4. Discovery port = TODO', '5. P2P listen port = TODO', '6. API port = TODO', @@ -43,6 +68,7 @@ export async function showConfigMenu(config) { config.logsDir = await showPathSelector(config.logsDir, true); break; case '3': + config.storageQuota = await showStorageQuotaSelector(config); break; case '4': break; diff --git a/src/handlers/installationHandlers.js b/src/handlers/installationHandlers.js index af36b62..fe0d380 100644 --- a/src/handlers/installationHandlers.js +++ b/src/handlers/installationHandlers.js @@ -81,10 +81,11 @@ export async function checkCodexInstallation(config, showNavigationMenu) { } } -async function saveCodexExePathToConfig(config, codexExePath) { +async function saveDefaultCodexConfig(config, codexExePath) { config.codexExe = codexExePath; config.dataDir = getCodexDataDirDefaultPath(); config.logsDir = getCodexLogsPath(); + config.storageQuota = 8 * 1024 * 1024 * 1024; if (!fs.existsSync(config.codexExe)) { console.log(showErrorMessage(`Codex executable not found in expected path: ${config.codexExe}`)); throw new Error("Exe not found"); @@ -128,7 +129,7 @@ export async function installCodex(config, showNavigationMenu) { await runCommand('curl -LO --ssl-no-revoke https://get.codex.storage/install.cmd'); await runCommand(`set "INSTALL_DIR=${installPath}" && "${process.cwd()}\\install.cmd"`); - await saveCodexExePathToConfig(config, path.join(installPath, "codex.exe")); + await saveDefaultCodexConfig(config, path.join(installPath, "codex.exe")); try { await runCommand('del /f install.cmd'); @@ -170,7 +171,7 @@ export async function installCodex(config, showNavigationMenu) { await runCommand(`INSTALL_DIR="${installPath}" timeout 120 bash install.sh`); } - await saveCodexExePathToConfig(config, path.join(installPath, "codex")); + await saveDefaultCodexConfig(config, path.join(installPath, "codex")); } catch (error) { if (error.message.includes('ECONNREFUSED') || error.message.includes('ETIMEDOUT')) { diff --git a/src/handlers/nodeHandlers.js b/src/handlers/nodeHandlers.js index b6dc09e..f9c4db8 100644 --- a/src/handlers/nodeHandlers.js +++ b/src/handlers/nodeHandlers.js @@ -85,7 +85,9 @@ export async function runCodex(config, showNavigationMenu) { const executable = config.codexExe; const args = [ `--data-dir="${config.dataDir}"`, + `--log-level=DEBUG`, `--log-file="${logFilePath}"`, + `--storage-quota="${config.storageQuota}"`, `--disc-port=${discPort}`, `--listen-addrs=/ip4/0.0.0.0/tcp/${listenPort}`, `--nat=${nat}`, diff --git a/src/services/config.js b/src/services/config.js index 7bc2f4a..353fd5b 100644 --- a/src/services/config.js +++ b/src/services/config.js @@ -8,8 +8,8 @@ const defaultConfig = { // TODO: // Save user-selected config options. Use these when starting Codex. dataDir: "", - logsDir: "" - // storageQuota: 0, + logsDir: "", + storageQuota: 0, // ports: { // discPort: 8090, // listenPort: 8070, diff --git a/src/utils/numberSelector.js b/src/utils/numberSelector.js new file mode 100644 index 0000000..0cb74b5 --- /dev/null +++ b/src/utils/numberSelector.js @@ -0,0 +1,47 @@ +import inquirer from 'inquirer'; + +function getMetricsMult(valueStr, allowMetricPostfixes) { + if (!allowMetricPostfixes) return 1; + const lower = valueStr.toLowerCase(); + if (lower.endsWith("tb") || lower.endsWith("t")) return Math.pow(1024, 4); + if (lower.endsWith("gb") || lower.endsWith("g")) return Math.pow(1024, 3); + if (lower.endsWith("mb") || lower.endsWith("m")) return Math.pow(1024, 2); + if (lower.endsWith("kb") || lower.endsWith("k")) return Math.pow(1024, 1); + return 1; +} + +function getNumericValue(valueStr) { + try { + const num = valueStr.match(/\d+/g); + const result = parseInt(num); + if (isNaN(result) || !isFinite(result)) { + throw new Error("Invalid input received."); + } + return result; + } catch (error) { + console.log("Failed to parse input: " + error.message); + throw error; + } +} + +async function promptForValueStr(promptMessage) { + const response = await inquirer.prompt([ + { + type: 'input', + name: 'valueStr', + message: promptMessage + }]); + return response.valueStr; +} + +export async function showNumberSelector(currentValue, promptMessage, allowMetricPostfixes) { + try { + var valueStr = await promptForValueStr(promptMessage); + valueStr = valueStr.replaceAll(" ", ""); + const mult = getMetricsMult(valueStr, allowMetricPostfixes); + const value = getNumericValue(valueStr); + return value * mult; + } catch { + return currentValue; + } +}