doorin-cli 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,162 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+ *.http
9
+
10
+ # Distribution / packaging
11
+ .Python
12
+ build/
13
+ develop-eggs/
14
+ dist/
15
+ downloads/
16
+ eggs/
17
+ .eggs/
18
+ lib/
19
+ lib64/
20
+ parts/
21
+ sdist/
22
+ var/
23
+ wheels/
24
+ pip-wheel-metadata/
25
+ share/python-wheels/
26
+ *.egg-info/
27
+ .installed.cfg
28
+ *.egg
29
+ MANIFEST
30
+
31
+ # PyInstaller
32
+ # Usually these files are written by a python script from a template
33
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
34
+ *.manifest
35
+ *.spec
36
+
37
+ # Installer logs
38
+ pip-log.txt
39
+ pip-delete-this-directory.txt
40
+
41
+ # Unit test / coverage reports
42
+ htmlcov/
43
+ .tox/
44
+ .nox/
45
+ .coverage
46
+ .coverage.*
47
+ .cache
48
+ nosetests.xml
49
+ coverage.xml
50
+ *.cover
51
+ *.py,cover
52
+ .hypothesis/
53
+ .pytest_cache/
54
+
55
+ # Translations
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+ *.sqlite3
64
+
65
+ # Flask stuff:
66
+ instance/
67
+ .webassets-cache
68
+
69
+ # Scrapy stuff:
70
+ .scrapy
71
+
72
+ # Sphinx documentation
73
+ docs/_build/
74
+
75
+ # PyBuilder
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ .python-version
87
+
88
+ # pipenv
89
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
90
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
91
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
92
+ # install all needed dependencies.
93
+ #Pipfile.lock
94
+
95
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
96
+ __pypackages__/
97
+
98
+ # SageMath parsed files
99
+ *.sage.py
100
+
101
+ # Environments
102
+ .env
103
+ .venv
104
+ .venv-speech/
105
+ .venv-cli/
106
+ .venv-toolbox/
107
+ .venv-rag/
108
+ .venv-agents/
109
+ .venv-sdk/
110
+ env/
111
+ venv/
112
+ ENV/
113
+ env.bak/
114
+ venv.bak/
115
+ staticfiles/
116
+ mediafiles/
117
+
118
+ # Spyder project settings
119
+ .spyderproject
120
+ .spyproject
121
+
122
+ # Rope project settings
123
+ .ropeproject
124
+
125
+ # mkdocs documentation
126
+ /site
127
+
128
+ # mypy
129
+ .mypy_cache/
130
+ .dmypy.json
131
+ dmypy.json
132
+
133
+ # Pyre type checker
134
+ .pyre/
135
+
136
+ # EDITOR
137
+ .idea
138
+
139
+ # NODEJS
140
+ node_modules/
141
+
142
+ # LOCAL ONLY
143
+ localonly/
144
+
145
+ # Whoosh index
146
+ whoosh/
147
+ whoosh_index/
148
+ .whoosh/
149
+ .whoosh_index/
150
+
151
+ export/
152
+ .export/
153
+
154
+ *.identifier
155
+ staticfiles/
156
+ redis/
157
+ minio/
158
+ postgresql/
159
+ notebooks/
160
+ volumes/
161
+ .artifacts/
162
+ .env
@@ -0,0 +1,8 @@
1
+ Metadata-Version: 2.4
2
+ Name: doorin-cli
3
+ Version: 0.1.0
4
+ Summary: Standalone Doorin Gateway Admin CLI
5
+ Requires-Python: >=3.12
6
+ Requires-Dist: httpx>=0.27.0
7
+ Requires-Dist: rich>=15.0.0
8
+ Requires-Dist: typer>=0.26.7
File without changes
@@ -0,0 +1 @@
1
+ # Doorin Gateway Standalone CLI
File without changes
@@ -0,0 +1,24 @@
1
+ import typer
2
+ from doorin_cli.common import console, DEFAULT_URL, DEFAULT_KEY
3
+ from doorin_cli.config_utils import save_config
4
+
5
+ app = typer.Typer(help="Manage CLI configuration", rich_markup_mode="rich")
6
+
7
+ @app.callback(invoke_without_command=True)
8
+ def config_main(ctx: typer.Context):
9
+ """
10
+ [bold green]Configure Doorin CLI settings.[/bold green]
11
+ Run without arguments to start interactive setup.
12
+ """
13
+ if ctx.invoked_subcommand is None:
14
+ url = typer.prompt("Doorin URL", default=DEFAULT_URL)
15
+ key = typer.prompt("Admin API Key", default=DEFAULT_KEY, hide_input=True)
16
+
17
+ save_config(url, key)
18
+ console.print(f"[green]Configuration saved to ~/.doorin_cli.json[/green]")
19
+
20
+ @app.command()
21
+ def show():
22
+ """[bold blue]Show current CLI configuration.[/bold blue]"""
23
+ console.print(f"[bold]URL:[/bold] {DEFAULT_URL}")
24
+ console.print(f"[bold]Key:[/bold] {'*' * len(DEFAULT_KEY) if DEFAULT_KEY else 'Not set'}")
@@ -0,0 +1,40 @@
1
+ import typer
2
+ from rich.table import Table
3
+ from doorin_cli.common import get_client, console, DEFAULT_URL, DEFAULT_KEY
4
+
5
+ app = typer.Typer(help="Manage Doorin Gateway routes", rich_markup_mode="rich")
6
+
7
+ @app.command("list")
8
+ def list_routes(
9
+ url: str = typer.Option(DEFAULT_URL, "--url", "-u", help="Doorin Gateway URL"),
10
+ key: str = typer.Option(DEFAULT_KEY, "--key", "-k", help="Admin API Key")
11
+ ):
12
+ """
13
+ [bold cyan]List all routes registered in the gateway.[/bold cyan]
14
+ Displays path, service, methods, and target URL for all active mappings.
15
+ """
16
+ try:
17
+ with get_client(url, key) as client:
18
+ resp = client.get("/admin/routes")
19
+ if resp.status_code == 403:
20
+ console.print("[red]Error: Unauthorized. Please check your admin API key.[/red]")
21
+ return
22
+
23
+ routes = resp.json()
24
+ table = Table(title="Doorin Gateway Routes")
25
+ table.add_column("Path", style="cyan")
26
+ table.add_column("Service ID", style="magenta")
27
+ table.add_column("Methods", style="green")
28
+ table.add_column("Target URL", style="blue")
29
+
30
+ for r in routes:
31
+ methods = ", ".join(r["config"].get("methods", []))
32
+ table.add_row(
33
+ r["path"],
34
+ r["service_id"] or "N/A",
35
+ methods,
36
+ r.get("target_url", "N/A")
37
+ )
38
+ console.print(table)
39
+ except Exception as e:
40
+ console.print(f"[red]Error:[/red] {e}")
@@ -0,0 +1,38 @@
1
+ import typer
2
+ from rich.table import Table
3
+ from doorin_cli.common import get_client, console, DEFAULT_URL, DEFAULT_KEY
4
+
5
+ app = typer.Typer(help="Manage Doorin Gateway services", rich_markup_mode="rich")
6
+
7
+ @app.command("list")
8
+ def list_services(
9
+ url: str = typer.Option(DEFAULT_URL, "--url", "-u", help="Doorin Gateway URL"),
10
+ key: str = typer.Option(DEFAULT_KEY, "--key", "-k", help="Admin API Key")
11
+ ):
12
+ """
13
+ [bold cyan]List all backend services configured in the gateway.[/bold cyan]
14
+ Displays service ID, base URL, and the default auth provider.
15
+ """
16
+ try:
17
+ with get_client(url, key) as client:
18
+ resp = client.get("/admin/services")
19
+ if resp.status_code == 403:
20
+ console.print("[red]Error: Unauthorized.[/red]")
21
+ return
22
+
23
+ services = resp.json()
24
+ table = Table(title="Doorin Gateway Services")
25
+ table.add_column("Service ID", style="cyan")
26
+ table.add_column("Base URL", style="green")
27
+ table.add_column("Auth Provider", style="magenta")
28
+
29
+ for s in services:
30
+ conf = s["config"]
31
+ table.add_row(
32
+ s["id"],
33
+ conf.get("base_url", "N/A"),
34
+ conf.get("default_auth_provider", "api_key")
35
+ )
36
+ console.print(table)
37
+ except Exception as e:
38
+ console.print(f"[red]Error:[/red] {e}")
@@ -0,0 +1,44 @@
1
+ import typer
2
+ from rich import print as rprint
3
+ from doorin_cli.common import get_client, DEFAULT_URL, DEFAULT_KEY
4
+
5
+ app = typer.Typer(help="Manage Doorin Gateway system", rich_markup_mode="rich")
6
+
7
+ @app.command()
8
+ def status(
9
+ url: str = typer.Option(DEFAULT_URL, "--url", "-u", help="Doorin Gateway URL"),
10
+ key: str = typer.Option(DEFAULT_KEY, "--key", "-k", help="Admin API Key")
11
+ ):
12
+ """
13
+ [bold green]Check gateway health status.[/bold green]
14
+ Connects to the /health endpoint to verify the gateway is responding.
15
+ """
16
+ try:
17
+ with get_client(url, key) as client:
18
+ resp = client.get("/health")
19
+ if resp.status_code == 200:
20
+ rprint(f"[bold green]✓[/bold green] Gateway at {url} is [green]healthy[/green]")
21
+ rprint(f"Response: {resp.json()}")
22
+ else:
23
+ rprint(f"[bold red]✗[/bold red] Gateway at {url} returned {resp.status_code}")
24
+ except Exception as e:
25
+ rprint(f"[bold red]Error connecting to {url}:[/bold red] {e}")
26
+
27
+ @app.command()
28
+ def reload(
29
+ url: str = typer.Option(DEFAULT_URL, "--url", "-u", help="Doorin Gateway URL"),
30
+ key: str = typer.Option(DEFAULT_KEY, "--key", "-k", help="Admin API Key")
31
+ ):
32
+ """
33
+ [bold yellow]Trigger a full configuration reload.[/bold yellow]
34
+ Tells the gateway to re-scan its YAML files and refresh the storage.
35
+ """
36
+ try:
37
+ with get_client(url, key) as client:
38
+ resp = client.post("/admin/reload")
39
+ if resp.status_code == 200:
40
+ rprint("[bold green]✓ Configuration reloaded successfully![/bold green]")
41
+ else:
42
+ rprint(f"[bold red]✗ Failed to reload:[/bold red] {resp.text}")
43
+ except Exception as e:
44
+ rprint(f"[red]Error:[/red] {e}")
@@ -0,0 +1,17 @@
1
+ import os
2
+ import httpx
3
+ from rich.console import Console
4
+
5
+ from doorin_cli.config_utils import load_config
6
+
7
+ console = Console()
8
+
9
+ # Load configuration (Priority: Env > Config File > Default)
10
+ _config = load_config()
11
+ DEFAULT_URL = os.getenv("DOORIN_URL", _config.get("url", "http://localhost:8000"))
12
+ DEFAULT_KEY = os.getenv("DOORIN_ADMIN_KEY", _config.get("key", ""))
13
+
14
+
15
+ def get_client(url: str, key: str):
16
+ headers = {"X-Admin-Key": key}
17
+ return httpx.Client(base_url=url, headers=headers, timeout=10.0)
@@ -0,0 +1,20 @@
1
+ import json
2
+ import os
3
+ from pathlib import Path
4
+
5
+ CONFIG_PATH = Path.home() / ".doorin_cli.json"
6
+
7
+ def save_config(url: str, key: str):
8
+ config = {
9
+ "url": url,
10
+ "key": key
11
+ }
12
+ CONFIG_PATH.write_text(json.dumps(config, indent=2))
13
+
14
+ def load_config():
15
+ if CONFIG_PATH.exists():
16
+ try:
17
+ return json.loads(CONFIG_PATH.read_text())
18
+ except Exception:
19
+ return {}
20
+ return {}
@@ -0,0 +1,25 @@
1
+ import typer
2
+ from doorin_cli.commands import routes, services, system, config
3
+
4
+ app = typer.Typer(
5
+ name="doorin-cli",
6
+ help="[bold cyan]Doorin Gateway Admin CLI[/bold cyan] 🚪",
7
+ add_completion=False,
8
+ rich_markup_mode="rich"
9
+ )
10
+
11
+ # Register sub-commands
12
+ app.add_typer(routes.app, name="routes", help="🔍 Inspect registered routes")
13
+ app.add_typer(services.app, name="services", help="🛠️ Manage backend services")
14
+ app.add_typer(system.app, name="system", help="⚙️ Gateway system operations")
15
+ app.add_typer(config.app, name="config", help="📝 Configure CLI settings (URL, API Key)")
16
+
17
+
18
+
19
+ # Also keep system commands at top level for convenience if desired,
20
+ # or just use the grouped ones. Let's keep status and reload at top level too.
21
+ app.command()(system.status)
22
+ app.command()(system.reload)
23
+
24
+ if __name__ == "__main__":
25
+ app()
@@ -0,0 +1,18 @@
1
+ [project]
2
+ name = "doorin-cli"
3
+ version = "0.1.0"
4
+ description = "Standalone Doorin Gateway Admin CLI"
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ dependencies = [
8
+ "httpx>=0.27.0",
9
+ "typer>=0.26.7",
10
+ "rich>=15.0.0",
11
+ ]
12
+
13
+ [project.scripts]
14
+ doorin-cli = "doorin_cli.main:app"
15
+
16
+ [build-system]
17
+ requires = ["hatchling"]
18
+ build-backend = "hatchling.build"