Fix database connection pool leak in init_db()
- Check if pool already exists before creating a new one - Set pool size limits (min=2, max=10) to prevent exhaustion - Multiple calls to init_db() were creating new pools without closing old ones, leading to "too many clients" errors Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
29
artdag.py
29
artdag.py
@@ -921,7 +921,8 @@ def import_file(filepath):
|
||||
|
||||
@cli.command()
|
||||
@click.argument("filepath", type=click.Path(exists=True))
|
||||
def upload(filepath):
|
||||
@click.option("--name", "-n", help="Friendly name for the asset")
|
||||
def upload(filepath, name):
|
||||
"""Upload a file to cache and IPFS. Requires login."""
|
||||
# Check auth
|
||||
token_data = load_token()
|
||||
@@ -932,8 +933,9 @@ def upload(filepath):
|
||||
try:
|
||||
with open(filepath, "rb") as f:
|
||||
files = {"file": (Path(filepath).name, f)}
|
||||
data = {"display_name": name} if name else {}
|
||||
headers = get_auth_header(require_token=True)
|
||||
resp = requests.post(f"{get_server()}/cache/upload", files=files, headers=headers)
|
||||
resp = requests.post(f"{get_server()}/cache/upload", files=files, data=data, headers=headers)
|
||||
if resp.status_code == 401:
|
||||
click.echo("Authentication failed. Please login again.", err=True)
|
||||
sys.exit(1)
|
||||
@@ -946,10 +948,12 @@ def upload(filepath):
|
||||
sys.exit(1)
|
||||
result = resp.json()
|
||||
click.echo(f"CID: {result['cid']}")
|
||||
click.echo(f"Friendly name: {result.get('friendly_name', 'N/A')}")
|
||||
click.echo(f"Size: {result['size']} bytes")
|
||||
click.echo()
|
||||
click.echo("Use in recipes:")
|
||||
click.echo(f' (asset my-asset :cid "{result["cid"]}")')
|
||||
friendly = result.get('friendly_name', result['cid'])
|
||||
click.echo(f' (streaming:make-video-source "{friendly}" 30)')
|
||||
except requests.RequestException as e:
|
||||
click.echo(f"Upload failed: {e}", err=True)
|
||||
sys.exit(1)
|
||||
@@ -1594,10 +1598,11 @@ def upload_recipe(filepath):
|
||||
|
||||
@cli.command("upload-effect")
|
||||
@click.argument("filepath", type=click.Path(exists=True))
|
||||
def upload_effect(filepath):
|
||||
@click.option("--name", "-n", help="Friendly name for the effect")
|
||||
def upload_effect(filepath, name):
|
||||
"""Upload an effect file to IPFS. Requires login.
|
||||
|
||||
Effects are Python files with PEP 723 dependencies and @-tag metadata.
|
||||
Effects are S-expression files (.sexp) with metadata in comments.
|
||||
Returns the IPFS CID for use in recipes.
|
||||
"""
|
||||
token_data = load_token()
|
||||
@@ -1605,17 +1610,18 @@ def upload_effect(filepath):
|
||||
click.echo("Not logged in. Please run: artdag login <username>", err=True)
|
||||
sys.exit(1)
|
||||
|
||||
# Check it's a Python file
|
||||
if not filepath.endswith(".py"):
|
||||
click.echo("Effect must be a Python file (.py)", err=True)
|
||||
# Check it's a sexp or py file
|
||||
if not filepath.endswith(".sexp") and not filepath.endswith(".py"):
|
||||
click.echo("Effect must be a .sexp or .py file", err=True)
|
||||
sys.exit(1)
|
||||
|
||||
# Upload
|
||||
try:
|
||||
with open(filepath, "rb") as f:
|
||||
files = {"file": (Path(filepath).name, f)}
|
||||
data = {"display_name": name} if name else {}
|
||||
headers = get_auth_header(require_token=True)
|
||||
resp = requests.post(f"{get_server()}/effects/upload", files=files, headers=headers)
|
||||
resp = requests.post(f"{get_server()}/effects/upload", files=files, data=data, headers=headers)
|
||||
if resp.status_code == 401:
|
||||
click.echo("Authentication failed. Please login again.", err=True)
|
||||
sys.exit(1)
|
||||
@@ -1627,14 +1633,13 @@ def upload_effect(filepath):
|
||||
|
||||
click.echo(f"Uploaded effect: {result['name']} v{result.get('version', '1.0.0')}")
|
||||
click.echo(f"CID: {result['cid']}")
|
||||
click.echo(f"Friendly name: {result.get('friendly_name', 'N/A')}")
|
||||
click.echo(f"Temporal: {result.get('temporal', False)}")
|
||||
if result.get('params'):
|
||||
click.echo(f"Parameters: {', '.join(p['name'] for p in result['params'])}")
|
||||
if result.get('dependencies'):
|
||||
click.echo(f"Dependencies: {', '.join(result['dependencies'])}")
|
||||
click.echo()
|
||||
click.echo("Use in recipes:")
|
||||
click.echo(f' (effect {result["name"]} :cid "{result["cid"]}")')
|
||||
click.echo(f' (effect {result["name"]} :name "{result.get("friendly_name", result["cid"])}")')
|
||||
except requests.RequestException as e:
|
||||
click.echo(f"Upload failed: {e}", err=True)
|
||||
sys.exit(1)
|
||||
|
||||
26
test_simple.sexp
Normal file
26
test_simple.sexp
Normal file
@@ -0,0 +1,26 @@
|
||||
;; Simple Test - No external assets required
|
||||
;; Just generates a color gradient that changes over time
|
||||
|
||||
(stream "simple_test"
|
||||
:fps 30
|
||||
:width 720
|
||||
:height 720
|
||||
:seed 42
|
||||
|
||||
;; Load standard primitives
|
||||
(require-primitives "geometry")
|
||||
(require-primitives "core")
|
||||
(require-primitives "math")
|
||||
(require-primitives "image")
|
||||
(require-primitives "color_ops")
|
||||
|
||||
;; Frame pipeline - animated gradient
|
||||
(frame
|
||||
(let [;; Time-based color cycling (0-1 range)
|
||||
r (+ 0.5 (* 0.5 (math:sin (* t 1))))
|
||||
g (+ 0.5 (* 0.5 (math:sin (* t 1.3))))
|
||||
b (+ 0.5 (* 0.5 (math:sin (* t 1.7))))
|
||||
;; Convert to 0-255 range and create solid color frame
|
||||
color [(* r 255) (* g 255) (* b 255)]
|
||||
frame (image:make-image 720 720 color)]
|
||||
frame)))
|
||||
Reference in New Issue
Block a user