main.js
1 #!/usr/bin/env node 2 3 import inquirer from "inquirer"; 4 import chalk from "chalk"; 5 import boxen from "boxen"; 6 import { ASCII_ART } from "./constants/ascii.js"; 7 import { 8 handleCommandLineOperation, 9 parseCommandLineArgs, 10 } from "./cli/commandParser.js"; 11 import { 12 uploadFile, 13 downloadFile, 14 showLocalFiles, 15 } from "./handlers/fileHandlers.js"; 16 import { 17 installCodex, 18 uninstallCodex, 19 } from "./handlers/installationHandlers.js"; 20 import { runCodex, checkNodeStatus } from "./handlers/nodeHandlers.js"; 21 import { showInfoMessage } from "./utils/messages.js"; 22 import { ConfigService } from "./services/configService.js"; 23 import { UiService } from "./services/uiService.js"; 24 import { FsService } from "./services/fsService.js"; 25 import { MainMenu } from "./ui/mainMenu.js"; 26 import { InstallMenu } from "./ui/installMenu.js"; 27 import { ConfigMenu } from "./ui/configMenu.js"; 28 import { PathSelector } from "./utils/pathSelector.js"; 29 import { NumberSelector } from "./utils/numberSelector.js"; 30 import { MenuLoop } from "./utils/menuLoop.js"; 31 import { Installer } from "./handlers/installer.js"; 32 import { ShellService } from "./services/shellService.js"; 33 import { OsService } from "./services/osService.js"; 34 import { ProcessControl } from "./handlers/processControl.js"; 35 import { CodexGlobals } from "./services/codexGlobals.js"; 36 import { CodexApp } from "./services/codexApp.js"; 37 import { EthersService } from "./services/ethersService.js"; 38 import { MarketplaceSetup } from "./ui/marketplaceSetup.js"; 39 import { DataService } from "./services/dataService.js"; 40 import { DataMenu } from "./ui/dataMenu.js"; 41 import { NodeStatusMenu } from "./ui/nodeStatusMenu.js"; 42 43 async function showNavigationMenu() { 44 console.log("\n"); 45 const { choice } = await inquirer.prompt([ 46 { 47 type: "list", 48 name: "choice", 49 message: "What would you like to do?", 50 choices: ["1. Back to main menu", "2. Exit"], 51 pageSize: 2, 52 loop: true, 53 }, 54 ]); 55 56 switch (choice.split(".")[0]) { 57 case "1": 58 return main(); 59 case "2": 60 handleExit(); 61 } 62 } 63 64 function handleExit() { 65 console.log( 66 boxen( 67 chalk.cyanBright("👋 Thank you for using Codex Storage CLI! Goodbye!"), 68 { 69 padding: 1, 70 margin: 1, 71 borderStyle: "round", 72 borderColor: "cyan", 73 title: "👋 GOODBYE", 74 titleAlignment: "center", 75 }, 76 ), 77 ); 78 process.exit(0); 79 } 80 81 export async function main() { 82 const commandArgs = parseCommandLineArgs(); 83 if (commandArgs) { 84 switch (commandArgs.command) { 85 case "upload": 86 await uploadFile( 87 commandArgs.value, 88 handleCommandLineOperation, 89 showNavigationMenu, 90 ); 91 return; 92 case "download": 93 await downloadFile( 94 commandArgs.value, 95 handleCommandLineOperation, 96 showNavigationMenu, 97 ); 98 return; 99 } 100 } 101 102 process.on("SIGINT", handleExit); 103 process.on("SIGTERM", handleExit); 104 process.on("SIGQUIT", handleExit); 105 106 const codexGlobals = new CodexGlobals(); 107 const uiService = new UiService(); 108 const fsService = new FsService(); 109 const shellService = new ShellService(); 110 const osService = new OsService(); 111 const numberSelector = new NumberSelector(uiService); 112 const configService = new ConfigService(fsService, osService); 113 const codexApp = new CodexApp(configService); 114 const pathSelector = new PathSelector(uiService, new MenuLoop(), fsService); 115 const ethersService = new EthersService( 116 fsService, 117 configService, 118 osService, 119 shellService, 120 ); 121 const marketplaceSetup = new MarketplaceSetup( 122 uiService, 123 configService, 124 ethersService, 125 ); 126 const installer = new Installer( 127 configService, 128 shellService, 129 osService, 130 fsService, 131 marketplaceSetup, 132 ); 133 const installMenu = new InstallMenu( 134 uiService, 135 new MenuLoop(), 136 configService, 137 pathSelector, 138 installer, 139 ); 140 const configMenu = new ConfigMenu( 141 uiService, 142 new MenuLoop(), 143 configService, 144 numberSelector, 145 ); 146 const processControl = new ProcessControl( 147 configService, 148 shellService, 149 osService, 150 fsService, 151 codexGlobals, 152 ); 153 const dataService = new DataService(configService); 154 const dataMenu = new DataMenu(uiService, fsService, dataService); 155 const nodeStatusMenu = new NodeStatusMenu( 156 uiService, 157 dataService, 158 new MenuLoop(), 159 ); 160 const mainMenu = new MainMenu( 161 uiService, 162 new MenuLoop(), 163 installMenu, 164 configMenu, 165 installer, 166 processControl, 167 codexApp, 168 dataMenu, 169 nodeStatusMenu, 170 ); 171 172 await mainMenu.show(); 173 return; 174 175 try { 176 while (true) { 177 console.log("\n" + chalk.cyanBright(ASCII_ART)); 178 const { choice } = await inquirer 179 .prompt([ 180 { 181 type: "list", 182 name: "choice", 183 message: "Select an option:", 184 choices: [ 185 "1. Download and install Codex", 186 "2. Run Codex node", 187 "3. Check node status", 188 "4. Edit Codex configuration", 189 "5. Open Codex App", 190 "6. Upload a file", 191 "7. Download a file", 192 "8. Show local data", 193 "9. Uninstall Codex node", 194 "10. Submit feedback", 195 "11. Exit", 196 ], 197 pageSize: 11, 198 loop: true, 199 }, 200 ]) 201 .catch(() => { 202 handleExit(); 203 return; 204 }); 205 206 switch (choice.split(".")[0]) { 207 case "1": 208 const installed = await installCodex(config, showNavigationMenu); 209 if (installed) { 210 await showConfigMenu(config); 211 } 212 break; 213 case "2": 214 await runCodex(config, showNavigationMenu); 215 return; 216 case "3": 217 await checkNodeStatus(config, showNavigationMenu); 218 break; 219 case "4": 220 await showConfigMenu(config); 221 break; 222 case "5": 223 openCodexApp(config); 224 break; 225 case "6": 226 await uploadFile( 227 config, 228 null, 229 handleCommandLineOperation, 230 showNavigationMenu, 231 ); 232 break; 233 case "7": 234 await downloadFile( 235 config, 236 null, 237 handleCommandLineOperation, 238 showNavigationMenu, 239 ); 240 break; 241 case "8": 242 await showLocalFiles(config, showNavigationMenu); 243 break; 244 case "9": 245 await uninstallCodex(config, showNavigationMenu); 246 break; 247 case "10": 248 const { exec } = await import("child_process"); 249 const url = "https://tally.so/r/w2DlXb"; 250 const command = 251 process.platform === "win32" 252 ? `start ${url}` 253 : process.platform === "darwin" 254 ? `open ${url}` 255 : `xdg-open ${url}`; 256 exec(command); 257 console.log( 258 showInfoMessage("Opening feedback form in your browser..."), 259 ); 260 break; 261 case "11": 262 handleExit(); 263 return; 264 } 265 266 console.log("\n"); 267 } 268 } catch (error) { 269 if (error.message.includes("ExitPromptError")) { 270 handleExit(); 271 } else { 272 console.error(chalk.red("An error occurred:", error.message)); 273 handleExit(); 274 } 275 } 276 }