/ src / main.js
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  }