Skip to content

Commit

Permalink
Use the pixlet API to render images
Browse files Browse the repository at this point in the history
The API method is faster than running the CLI because it doesn't
require launching additional processes and has a functional HTTP
cache.

Requires tronbyt/pixlet#6
  • Loading branch information
IngmarStein committed Feb 16, 2025
1 parent 4b5f613 commit ca6128f
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 44 deletions.
6 changes: 3 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ FROM ghcr.io/tavdog/pixlet:latest AS pixlet-builder
# build runtime image
FROM alpine:edge AS runtime

# 8000 for main app, 5100, 5101 for pixlet serve iframe
# 8000 for main app, 5100, 5101 for pixlet serve iframe
EXPOSE 8000 5100 5101

ENV PYTHONUNBUFFERED=1
Expand All @@ -14,9 +14,9 @@ WORKDIR /app
COPY --from=pixlet-builder /bin/pixlet /pixlet/pixlet

RUN apk --no-cache add esptool --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing/ && \
apk --no-cache add python3 py3-flask py3-gunicorn py3-dotenv \
apk --no-cache add python3 py3-flask py3-gunicorn py3-dotenv py3-requests \
libwebp libwebpmux libwebpdemux \
procps-ng git tzdata
procps-ng git tzdata ca-certificates

COPY . /app

Expand Down
12 changes: 12 additions & 0 deletions docker-compose.dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,15 @@ services:
- PYTHONUNBUFFERED=1
- SYSTEM_APPS_REPO=${SYSTEM_APPS_REPO}
- PRODUCTION=${PRODUCTION}
- PIXLET_API_URL=http://pixlet:8080
depends_on:
- pixlet
links:
- pixlet
pixlet:
image: ghcr.io/ingmarstein/pixlet:latest
command: ["api", "--host=0.0.0.0", "--port=8080"]
container_name: pixlet
volumes:
- .:/app # for development
- "/etc/localtime:/etc/localtime:ro" # used to sync docker with host time
13 changes: 13 additions & 0 deletions docker-compose.https.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,19 @@ services:
- PIXLET_RENDER_PORT1=${PIXLET_SERVE_PORT1}
- SYSTEM_APPS_REPO=${SYSTEM_APPS_REPO}
- PRODUCTION=${PRODUCTION}
- PIXLET_API_URL=http://pixlet:8080
depends_on:
- pixlet
links:
- pixlet
pixlet:
image: ghcr.io/tavdog/pixlet:latest
command: ["api", "--host=0.0.0.0", "--port=8080"]
container_name: pixlet
restart: unless-stopped
volumes:
- .:/app # for development
- "/etc/localtime:/etc/localtime:ro" # used to sync docker with host time
proxy:
image: caddy:latest
restart: unless-stopped
Expand Down
18 changes: 17 additions & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,28 @@ services:
- "/etc/localtime:/etc/localtime:ro" # used to sync docker with host time
- users:/app/users
- webp:/app/tronbyt_server/webp
- systemapps:/app/system-apps
environment:
- SERVER_HOSTNAME=${SERVER_HOSTNAME_OR_IP:?SERVER_HOSTNAME_OR_IP MUST BE SET IN .env FILE !!!!!!!!!!!!!!!!!.}
- SERVER_PORT=${SERVER_PORT}
- PIXLET_RENDER_PORT1=${PIXLET_SERVE_PORT1}
- SYSTEM_APPS_REPO=${SYSTEM_APPS_REPO}
- PRODUCTION=${PRODUCTION}
- PIXLET_API_URL=http://pixlet:8080
depends_on:
- pixlet
links:
- pixlet
pixlet:
image: ghcr.io/ingmarstein/pixlet:latest
command: ["api", "--host=0.0.0.0", "--port=8080"]
container_name: pixlet
restart: unless-stopped
volumes:
- users:/app/users
- systemapps:/app/system-apps # for development
- "/etc/localtime:/etc/localtime:ro" # used to sync docker with host time
volumes:
users:
webp:
webp:
systemapps:
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
flask
gunicorn
python-dotenv
esptool
esptool
requests
2 changes: 2 additions & 0 deletions tronbyt_server/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ def create_app(test_config=None):
SERVER_PROTOCOL=os.getenv("SERVER_PROTOCOL", "http"),
PIXLET_RENDER_PORT1=os.getenv("PIXLET_RENDER_PORT1", "5100"),
MAIN_PORT=os.getenv("SERVER_PORT", "8000"),
PIXLET_API_URL=os.getenv("PIXLET_API_URL", ""),
USERS_DIR="users",
DB_FILE="usersdb.sqlite",
)
Expand All @@ -30,6 +31,7 @@ def create_app(test_config=None):
DB_FILE="testdb.sqlite",
SERVER_HOSTNAME="localhost",
MAIN_PORT=os.getenv("SERVER_PORT", "8000"),
PIXLET_API_URL=os.getenv("PIXLET_API_URL", ""),
USERS_DIR="tests/users",
PRODUCTION=0,
TESTING=True,
Expand Down
91 changes: 52 additions & 39 deletions tronbyt_server/manager.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import json
import os
import secrets
import string
import subprocess
import time
import uuid

import requests
from flask import (
Blueprint,
Response,
Expand Down Expand Up @@ -479,6 +481,53 @@ def updateapp(device_id, iname):
return render_template("manager/updateapp.html", app=app, device_id=device_id)


def render_app(app_path, config_path, webp_path):
pixlet_api_url = current_app.config["PIXLET_API_URL"]
if pixlet_api_url != "":
print("rendering app via pixlet API")
with open(config_path, "r") as config_file:
config_data = json.load(config_file)
response = requests.post(
f"{pixlet_api_url}/api/render",
json={"path": f"/app/{app_path}", "config": config_data},
)
if response.status_code == 200:
with open(webp_path, "wb") as f:
f.write(response.content)
return True
else:
print(
f"Error rendering app via pixlet API, trying CLI: {response.status_code} {response.text}"
)

# build the pixlet render command
if os.path.exists(config_path):
command = [
"/pixlet/pixlet",
"render",
"-c",
config_path,
app_path,
"-o",
webp_path,
]
else: # if the path doesn't exist then don't include it in render command
command = [
"/pixlet/pixlet",
"render",
app_path,
"-o",
webp_path,
]
# print(command)
result = subprocess.run(command)
if result.returncode != 0:
print("\t\t\tError running pixlet render")
print(result)
return False
return True


def possibly_render(user, device_id, app):
result = False
if "pushed" in app:
Expand Down Expand Up @@ -506,31 +555,7 @@ def possibly_render(user, device_id, app):
or now - app["last_render"] > int(app["uinterval"]) * 60
):
print(f"\nRENDERING -- {app_basename}")
# build the pixlet render command
if os.path.exists(config_path):
command = [
"/pixlet/pixlet",
"render",
"-c",
config_path,
app_path,
"-o",
webp_path,
]
else: # if the path doesn't exist then don't include it in render command
command = [
"/pixlet/pixlet",
"render",
app_path,
"-o",
webp_path,
]
# print(command)
result = subprocess.run(command)
if result.returncode != 0:
print("\t\t\tError running pixlet render")
print(result)
else:
if render_app(app_path, config_path, webp_path):
# update the config file with the new last render time
app["last_render"] = int(time.time())
result = True
Expand Down Expand Up @@ -634,20 +659,8 @@ def configapp(device_id, iname, delete_on_cancel):

# run pixlet render with the new config file
print("rendering")
# render_result = os.system("/pixlet/pixlet render -c {} {} -o {}".format(config_path, app_path, webp_path))
render_result = subprocess.run(
[
"/pixlet/pixlet",
"render",
"-c",
config_path,
app_path,
"-o",
webp_path,
]
)
device = g.user["devices"][device_id]
if render_result.returncode == 0: # success
if render_app(app_path, config_path, webp_path):
# set the enabled key in app to true now that it has been configured.
device["apps"][iname]["enabled"] = "true"
# set last_rendered to seconds
Expand All @@ -674,7 +687,7 @@ def configapp(device_id, iname, delete_on_cancel):
if "deleted" in app:
del app["deleted"]
else:
# delete installation may error if the instlalation doesn't exist but that's ok.
# delete installation may error if the installation doesn't exist but that's ok.
command = [
"/pixlet/pixlet",
"delete",
Expand Down

0 comments on commit ca6128f

Please sign in to comment.