-
-
Notifications
You must be signed in to change notification settings - Fork 854
feat: add abdm-cli IPC companion CLI #1313
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ID-VerNe
wants to merge
3
commits into
amir1376:master
Choose a base branch
from
ID-VerNe:cli-ipc
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,184 @@ | ||
| # AB Download Manager CLI (`abdm-cli`) | ||
|
|
||
| `abdm-cli` is a **desktop companion CLI** for AB Download Manager. It is **not** a standalone download manager — it acts as an IPC client that connects to the running desktop app's embedded HTTP server. | ||
|
|
||
| ## Design | ||
|
|
||
| - **IPC client only** — the desktop app is the single source of truth for all download state. | ||
| - **Auto-start** — when the desktop app is not running, `abdm-cli` starts it in the background and waits for it to be ready. | ||
| - **Port reading** — the CLI reads the integration port from `~/.abdm/config/appSettings.json` (key: `browserIntegrationPort`). | ||
| - **HTTP client** — uses http4k with OkHttp, matching the existing SingleInstance communication stack in the desktop app. | ||
|
|
||
| ## Commands | ||
|
|
||
| | Command | Description | | ||
| |---------|-------------| | ||
| | [`add`](#add) | Add a new download | | ||
| | [`list`](#list) | List all downloads | | ||
| | [`info`](#info) | Show detailed information about a download | | ||
| | [`pause`](#pause) | Pause one or more downloads | | ||
| | [`resume`](#resume) | Resume one or more downloads | | ||
| | [`remove`](#remove) | Remove one or more downloads | | ||
|
|
||
| Global options: | ||
|
|
||
| | Option | Description | | ||
| |--------|-------------| | ||
| | `--help`, `-h` | Show help message and exit | | ||
| | `--version` | Show version and exit | | ||
|
|
||
| --- | ||
|
|
||
| ### `add` | ||
|
|
||
| Add a new download from a URL. | ||
|
|
||
| ```bash | ||
| abdm-cli add <url> | ||
| ``` | ||
|
|
||
| The command returns the assigned download ID and file name on success. | ||
|
|
||
| --- | ||
|
|
||
| ### `list` | ||
|
|
||
| List all current downloads. | ||
|
|
||
| ```bash | ||
| abdm-cli list | ||
| abdm-cli list --all | ||
| abdm-cli list --json | ||
| ``` | ||
|
|
||
| | Option | Description | | ||
| |--------|-------------| | ||
| | `--all` | Show all downloads, including completed ones | | ||
| | `--json` | Output results as JSON instead of a table | | ||
|
|
||
| Without `--all`, only active (downloading/paused) downloads are shown. | ||
|
|
||
| --- | ||
|
|
||
| ### `info` | ||
|
|
||
| Show detailed information for a specific download. | ||
|
|
||
| ```bash | ||
| abdm-cli info <id> | ||
| ``` | ||
|
|
||
| Displays file name, URL, progress, speed, ETA, status, and other metadata. | ||
|
|
||
| --- | ||
|
|
||
| ### `pause` | ||
|
|
||
| Pause one or more active downloads. | ||
|
|
||
| ```bash | ||
| abdm-cli pause <id>... | ||
| ``` | ||
|
|
||
| Accepts one or more download IDs separated by spaces. | ||
|
|
||
| --- | ||
|
|
||
| ### `resume` | ||
|
|
||
| Resume one or more paused downloads. | ||
|
|
||
| ```bash | ||
| abdm-cli resume <id>... | ||
| ``` | ||
|
|
||
| Accepts one or more download IDs separated by spaces. | ||
|
|
||
| --- | ||
|
|
||
| ### `remove` | ||
|
|
||
| Remove one or more downloads from the list. | ||
|
|
||
| ```bash | ||
| abdm-cli remove <id>... | ||
| abdm-cli remove --keep-file <id>... | ||
| ``` | ||
|
|
||
| | Option | Description | | ||
| |--------|-------------| | ||
| | `--keep-file`, `-k` | Keep the downloaded file on disk (default: **enabled**) | | ||
|
|
||
| **Safety default:** completed files are **kept** by default. To delete a completed file, you must explicitly opt out (this flag is a no-op for macOS/Linux; it is planned for a future release). | ||
|
|
||
| ## Examples | ||
|
|
||
| ```bash | ||
| # Add a download | ||
| abdm-cli add https://example.com/file.zip | ||
|
|
||
| # List active downloads | ||
| abdm-cli list | ||
|
|
||
| # List all downloads (including completed) as JSON | ||
| abdm-cli list --all --json | ||
|
|
||
| # Show details for download #42 | ||
| abdm-cli info 42 | ||
|
|
||
| # Pause downloads #5 and #7 | ||
| abdm-cli pause 5 7 | ||
|
|
||
| # Resume downloads #5 and #7 | ||
| abdm-cli resume 5 7 | ||
|
|
||
| # Remove download #12 (keeps the file on disk) | ||
| abdm-cli remove 12 | ||
|
|
||
| # Remove download #12 and delete the file | ||
| abdm-cli remove 12 --keep-file=false | ||
| ``` | ||
|
|
||
| ## Installation | ||
|
|
||
| On Windows, `abdm-cli` is bundled with the NSIS installer. The installer includes an optional "Add AB Download Manager to PATH" checkbox (disabled by default). | ||
|
|
||
| After installation with PATH enabled, `abdm-cli` is available from any terminal: | ||
|
|
||
| ```bash | ||
| abdm-cli --help | ||
| ``` | ||
|
|
||
| If PATH is not enabled, you can run the CLI directly from the install directory: | ||
|
|
||
| ```bash | ||
| "C:\Program Files\ABDownloadManager\abdm-cli.bat" --help | ||
| ``` | ||
|
|
||
| ## Platform Support | ||
|
|
||
| | Platform | Status | | ||
| |----------|--------| | ||
| | Windows | ✅ Supported (NSIS installer, registry-based discovery) | | ||
| | Linux | ⏳ Planned (follow-up) | | ||
| | macOS | ⏳ Planned (follow-up) | | ||
|
|
||
| The CLI implementation is platform-neutral. Packaging and PATH integration for Linux and macOS will be added in future releases. | ||
|
|
||
| ## Build | ||
|
|
||
| ```bash | ||
| # Build the CLI fat JAR | ||
| ./gradlew :cli:app:shadowJar -Pjvm.toolchain=21 | ||
|
|
||
| # Build the Windows installer (includes the CLI) | ||
| ./gradlew :desktop:app:createInstallerNsis -Pjvm.toolchain=21 | ||
| ``` | ||
|
|
||
| ## Implementation Details | ||
|
|
||
| - Built with **Clikt** (command-line parsing) and **Mordant** (terminal output formatting). | ||
| - The CLI fat JAR is produced by the **Shadow** plugin (`com.gradleup.shadow`). | ||
| - The CLI reuses the desktop app's bundled JRE — no system Java installation is required. | ||
| - `java.management` module is added to the runtime image because Mordant terminal detection requires it. | ||
| - All commands communicate through HTTP to the desktop app's embedded server. | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please remove the distribution logic. I will add support for additional launchers and add an extra launcher to support all platforms |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| import buildlogic.versioning.getAppVersionString | ||
|
|
||
| plugins { | ||
| kotlin("jvm") | ||
| kotlin("plugin.serialization") | ||
| application | ||
| id(Plugins.buildConfig) | ||
| alias(libs.plugins.shadow) | ||
| } | ||
|
|
||
| dependencies { | ||
| // Project modules — DTOs + shared utilities (datasize) | ||
| implementation(project(":integration:server")) | ||
| implementation(project(":shared:utils")) | ||
|
|
||
| // Kotlin | ||
| implementation(libs.kotlin.coroutines.core) | ||
| implementation(libs.kotlin.serialization.json) | ||
|
|
||
| // CLI framework | ||
| implementation("com.github.ajalt.clikt:clikt:4.4.0") | ||
| implementation("com.github.ajalt.mordant:mordant:2.7.2") | ||
|
|
||
| // HTTP client (same http4k + OkHttp stack as desktop app) | ||
| implementation(libs.http4k.core) | ||
| implementation(libs.http4k.client.okhttp) | ||
|
|
||
| // Test dependencies | ||
| testImplementation(kotlin("test")) | ||
| testImplementation("junit:junit:4.13.2") | ||
| } | ||
|
|
||
| application { | ||
| mainClass = "com.abdownloadmanager.cli.CliMainKt" | ||
| applicationName = "abdm-cli" | ||
| applicationDefaultJvmArgs = listOf("-Djava.awt.headless=true") | ||
| } | ||
|
|
||
| tasks.named<JavaExec>("run") { | ||
| standardInput = System.`in` | ||
| } | ||
|
|
||
| // Generate build config with version from the project's shared versioning | ||
| buildConfig { | ||
| packageName = "com.abdownloadmanager.cli" | ||
| buildConfigField( | ||
| "APP_VERSION", | ||
| provider { getAppVersionString() } | ||
| ) | ||
| } | ||
|
|
||
| // Configure shadow JAR packaging for the CLI fat JAR | ||
| tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") { | ||
| archiveBaseName.set("abdm-cli") | ||
| archiveClassifier.set("") | ||
| mergeServiceFiles() | ||
| exclude("META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA") | ||
| } |
60 changes: 60 additions & 0 deletions
60
cli/app/src/main/kotlin/com/abdownloadmanager/cli/CliMain.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| package com.abdownloadmanager.cli | ||
|
|
||
| import com.abdownloadmanager.cli.BuildConfig | ||
| import com.abdownloadmanager.cli.commands.* | ||
| import com.github.ajalt.clikt.core.CliktCommand | ||
| import com.github.ajalt.clikt.core.PrintHelpMessage | ||
| import com.github.ajalt.clikt.core.PrintCompletionMessage | ||
| import com.github.ajalt.clikt.core.subcommands | ||
| import com.github.ajalt.clikt.parameters.options.versionOption | ||
| import com.github.ajalt.mordant.rendering.TextColors | ||
| import com.github.ajalt.mordant.terminal.Terminal | ||
|
|
||
| private const val DEBUG_MODE = false | ||
|
|
||
| class CliApp : CliktCommand( | ||
| name = "abdm-cli", | ||
| help = "AB Download Manager CLI — IPC client for the desktop app", | ||
| ) { | ||
| init { | ||
| versionOption(BuildConfig.APP_VERSION) | ||
| } | ||
|
|
||
| override fun run() { | ||
| if (currentContext.invokedSubcommand == null) { | ||
| echo("AB Download Manager CLI") | ||
| echo("Use --help to see available commands.") | ||
| } | ||
| } | ||
| } | ||
|
|
||
| fun main(args: Array<String>) { | ||
| try { | ||
| val app = CliApp().subcommands( | ||
| AddCommand(), | ||
| ListCommand(), | ||
| InfoCommand(), | ||
| PauseCommand(), | ||
| ResumeCommand(), | ||
| RemoveCommand(), | ||
| ) | ||
|
|
||
| app.main(args) | ||
| // Force exit — OkHttp non-daemon threads keep JVM alive | ||
| System.exit(0) | ||
| } catch (e: PrintHelpMessage) { | ||
| System.exit(0) | ||
| } catch (e: PrintCompletionMessage) { | ||
| System.exit(0) | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we are in kotlin exitProcess(0) |
||
| } catch (e: com.github.ajalt.clikt.core.CliktError) { | ||
| // Clikt prints the error message to stderr internally | ||
| System.exit(64) | ||
| } catch (e: Exception) { | ||
| val term = Terminal() | ||
| term.println((TextColors.red)("Error: ${e.message ?: e::class.simpleName ?: "Unknown error"}")) | ||
| if (DEBUG_MODE) { | ||
| e.printStackTrace() | ||
| } | ||
| System.exit(1) | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove this section