mirror of
https://github.com/Screenly/Anthias.git
synced 2026-08-03 19:23:46 -04:00
With both legs of the viewer signalling path on Redis (PR1: command
bus, PR2: reply bus), the pyzmq runtime dependency and the libzmq*
build deps are no longer used.
- pyproject.toml: remove pyzmq==23.2.1 from server, viewer,
wifi-connect, and mypy dep groups (4 places).
- uv.lock: regenerated; pyzmq + transitive py drop out.
- tools/image_builder/{__main__,utils}.py: remove libzmq3-dev /
libzmq5-dev / libzmq5 from the base apt list and from the viewer
context's apt list. docker/uv-builder.j2 likewise drops libzmq3-dev
from both the prebuilt-uv branch and the pip-fallback branch (32-bit
ARM). The rendered docker/Dockerfile.* artifacts are gitignored, so
no committed Dockerfile churn here — they regenerate cleanly via
`python -m tools.image_builder --dockerfiles-only`.
- send_zmq_message.py → send_viewer_message.py. The script already
publishes via Redis (fixed in the PR1 follow-up); rename + update
callers (bin/start_wifi_connect.sh, docker/Dockerfile.wifi-connect.j2)
now that the ZMQ name is misleading.
- bin/start_server.sh: drop the stale "single-worker because
ZmqPublisher binds 10001" comment. The publisher is now a Redis
client — no port bind, multi-worker is safe whenever the operator
wants to opt in (not changed in this PR).
- CLAUDE.md: update the architecture description (ZMQ ports 10001 /
5558 are gone, Redis carries the viewer signalling traffic now).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
342 lines
9.0 KiB
Python
342 lines
9.0 KiB
Python
from typing import Any
|
|
|
|
import click
|
|
import requests
|
|
from jinja2 import Environment, FileSystemLoader
|
|
|
|
from tools.image_builder.constants import GITHUB_REPO_URL
|
|
|
|
|
|
def get_build_parameters(build_target: str) -> dict[str, Any]:
|
|
default_build_parameters = {
|
|
'board': 'x86',
|
|
'base_image': 'debian',
|
|
'target_platform': 'linux/amd64',
|
|
}
|
|
|
|
if build_target == 'pi5':
|
|
return {
|
|
'board': 'pi5',
|
|
'base_image': 'balenalib/raspberrypi5-debian',
|
|
'target_platform': 'linux/arm64/v8',
|
|
}
|
|
if build_target == 'pi4':
|
|
return {
|
|
'board': 'pi4',
|
|
'base_image': 'balenalib/raspberrypi3-debian',
|
|
'target_platform': 'linux/arm/v8',
|
|
}
|
|
elif build_target == 'pi4-64':
|
|
return {
|
|
'board': 'pi4',
|
|
'base_image': 'balenalib/raspberrypi3-debian',
|
|
'target_platform': 'linux/arm64/v8',
|
|
}
|
|
elif build_target == 'pi3':
|
|
return {
|
|
'board': 'pi3',
|
|
'base_image': 'balenalib/raspberrypi3-debian',
|
|
'target_platform': 'linux/arm/v7',
|
|
}
|
|
elif build_target == 'pi2':
|
|
return {
|
|
'board': 'pi2',
|
|
'base_image': 'balenalib/raspberry-pi2',
|
|
'target_platform': 'linux/arm/v6',
|
|
}
|
|
elif build_target == 'pi1':
|
|
return {
|
|
'board': 'pi1',
|
|
'base_image': 'balenalib/raspberry-pi',
|
|
'target_platform': 'linux/arm/v6',
|
|
}
|
|
|
|
return default_build_parameters
|
|
|
|
|
|
def get_docker_tag(git_branch: str, board: str, platform: str) -> str:
|
|
result_board = board
|
|
|
|
if platform == 'linux/arm64/v8' and board == 'pi4':
|
|
result_board = f'{board}-64'
|
|
|
|
if git_branch == 'master':
|
|
return f'latest-{result_board}'
|
|
else:
|
|
return f'{git_branch}-{result_board}'
|
|
|
|
|
|
def generate_dockerfile(service: str, context: dict[str, Any]) -> None:
|
|
templating_environment = Environment(loader=FileSystemLoader('docker/'))
|
|
templating_environment.lstrip_blocks = True
|
|
templating_environment.trim_blocks = True
|
|
|
|
template = templating_environment.get_template(f'Dockerfile.{service}.j2')
|
|
dockerfile = template.render(**context)
|
|
|
|
with open(f'docker/Dockerfile.{service}', 'w') as f:
|
|
f.write(dockerfile)
|
|
|
|
|
|
def get_uv_builder_context(service: str) -> dict[str, Any]:
|
|
service_to_group = {
|
|
'server': 'server',
|
|
'celery': 'server',
|
|
'wifi-connect': 'wifi-connect',
|
|
'viewer': 'viewer',
|
|
'test': 'test',
|
|
}
|
|
|
|
uv_group = service_to_group.get(service)
|
|
if uv_group is None:
|
|
return {}
|
|
|
|
groups_needing_native_build_libs = {'server', 'viewer', 'test'}
|
|
builder_extra_apt = []
|
|
if uv_group in groups_needing_native_build_libs:
|
|
builder_extra_apt = [
|
|
'libcec-dev',
|
|
'libdbus-1-dev',
|
|
'libdbus-glib-1-dev',
|
|
]
|
|
|
|
return {
|
|
'uv_group': uv_group,
|
|
'builder_extra_apt': builder_extra_apt,
|
|
'uv_system_site_packages': service in {'viewer', 'test'},
|
|
}
|
|
|
|
|
|
def get_test_context() -> dict[str, Any]:
|
|
chrome_dl_url = (
|
|
'https://storage.googleapis.com/chrome-for-testing-public/'
|
|
'123.0.6312.86/linux64/chrome-linux64.zip'
|
|
)
|
|
chromedriver_dl_url = (
|
|
'https://storage.googleapis.com/chrome-for-testing-public/'
|
|
'123.0.6312.86/linux64/chromedriver-linux64.zip'
|
|
)
|
|
|
|
return {
|
|
'apt_dependencies': [
|
|
'wget',
|
|
'unzip',
|
|
'libnss3',
|
|
'libatk1.0-0',
|
|
'libatk-bridge2.0.0',
|
|
'libcups2',
|
|
'libxcomposite1',
|
|
'libxdamage1',
|
|
],
|
|
'chrome_dl_url': chrome_dl_url,
|
|
'chromedriver_dl_url': chromedriver_dl_url,
|
|
}
|
|
|
|
|
|
def get_viewer_context(board: str) -> dict[str, Any]:
|
|
releases_url = f'{GITHUB_REPO_URL}/releases/download'
|
|
|
|
webview_git_hash = 'd7a7e2c'
|
|
webview_base_url = f'{releases_url}/WebView-v0.3.12'
|
|
|
|
qt_version = '5.15.14'
|
|
|
|
if board in ['pi5', 'x86']:
|
|
qt_version = '6.4.2'
|
|
else:
|
|
qt_version = '5.15.14'
|
|
|
|
qt_major_version = qt_version.split('.')[0]
|
|
|
|
apt_dependencies = [
|
|
'build-essential',
|
|
'ca-certificates',
|
|
'curl',
|
|
'dbus-daemon',
|
|
'fonts-arphic-uming',
|
|
'git-core',
|
|
'libasound2-dev',
|
|
'libavcodec-dev',
|
|
'libavformat-dev',
|
|
'libavutil-dev',
|
|
'libbz2-dev',
|
|
'libcec-dev ',
|
|
'libdbus-1-dev',
|
|
'libdbus-glib-1-dev',
|
|
'libdrm-dev',
|
|
'libegl1-mesa-dev',
|
|
'libevent-dev',
|
|
'libffi-dev',
|
|
'libfontconfig1-dev',
|
|
'libfreetype6-dev',
|
|
'libgbm-dev',
|
|
'libgcrypt20-dev',
|
|
'libgles2-mesa',
|
|
'libgles2-mesa-dev',
|
|
'libglib2.0-dev',
|
|
'libicu-dev',
|
|
'libinput-dev',
|
|
'libiodbc2-dev',
|
|
'libjpeg62-turbo-dev',
|
|
'libjsoncpp-dev',
|
|
'libminizip-dev',
|
|
'libnss3',
|
|
'libnss3-dev',
|
|
'libnss3-tools',
|
|
'libopus-dev',
|
|
'libpci-dev',
|
|
'libpng-dev',
|
|
'libpng16-16',
|
|
'libpq-dev',
|
|
'libpulse-dev',
|
|
'librsvg2-common',
|
|
'libsdl2-dev',
|
|
'libsnappy-dev',
|
|
'libsqlite3-dev',
|
|
'libsrtp2-dev',
|
|
'libssl-dev',
|
|
'libswscale-dev',
|
|
'libsystemd-dev',
|
|
'libts-dev',
|
|
'libudev-dev',
|
|
'libvpx-dev',
|
|
'libwebp-dev',
|
|
'libx11-dev',
|
|
'libx11-xcb-dev',
|
|
'libx11-xcb1',
|
|
'libxcb-glx0-dev',
|
|
'libxcb-icccm4',
|
|
'libxcb-icccm4-dev',
|
|
'libxcb-image0',
|
|
'libxcb-image0-dev',
|
|
'libxcb-keysyms1',
|
|
'libxcb-keysyms1-dev',
|
|
'libxcb-randr0-dev',
|
|
'libxcb-render-util0',
|
|
'libxcb-render-util0-dev',
|
|
'libxcb-shape0-dev',
|
|
'libxcb-shm0',
|
|
'libxcb-shm0-dev',
|
|
'libxcb-sync-dev',
|
|
'libxcb-sync1',
|
|
'libxcb-xfixes0-dev',
|
|
'libxcb-xinerama0',
|
|
'libxcb-xinerama0-dev',
|
|
'libxcb1',
|
|
'libxcb1-dev',
|
|
'libxext-dev',
|
|
'libxi-dev',
|
|
'libxkbcommon-dev',
|
|
'libxrender-dev',
|
|
'libxslt1-dev',
|
|
'libxss-dev',
|
|
'libxtst-dev',
|
|
'net-tools',
|
|
'procps',
|
|
'psmisc',
|
|
'python3-dev',
|
|
'python3-gi',
|
|
'python3-netifaces',
|
|
'python3-pip',
|
|
'python3-setuptools',
|
|
'python-is-python3',
|
|
'ttf-wqy-zenhei',
|
|
'vlc',
|
|
'sudo',
|
|
'sqlite3',
|
|
'ffmpeg',
|
|
'libavcodec-dev',
|
|
'libavdevice-dev',
|
|
'libavfilter-dev',
|
|
'libavformat-dev',
|
|
'libavutil-dev',
|
|
'libswresample-dev',
|
|
'libswscale-dev',
|
|
]
|
|
|
|
if board in ['pi5', 'x86']:
|
|
apt_dependencies.extend(
|
|
[
|
|
'mpv',
|
|
'qt6-base-dev',
|
|
'qt6-webengine-dev',
|
|
'qt6-image-formats-plugins',
|
|
]
|
|
)
|
|
|
|
if board not in ['x86', 'pi5']:
|
|
apt_dependencies.extend(
|
|
[
|
|
'libraspberrypi0',
|
|
'libgst-dev',
|
|
'libsqlite0-dev',
|
|
'libsrtp0-dev',
|
|
'qt5-image-formats-plugins',
|
|
]
|
|
)
|
|
|
|
if board != 'pi1':
|
|
apt_dependencies.extend(['libssl1.1'])
|
|
|
|
return {
|
|
'apt_dependencies': apt_dependencies,
|
|
'qt_version': qt_version,
|
|
'qt_major_version': qt_major_version,
|
|
'webview_git_hash': webview_git_hash,
|
|
'webview_base_url': webview_base_url,
|
|
}
|
|
|
|
|
|
def get_wifi_connect_context(target_platform: str) -> dict[str, Any]:
|
|
if target_platform == 'linux/arm/v6':
|
|
architecture = 'rpi'
|
|
elif target_platform in ['linux/arm/v7', 'linux/arm/v8']:
|
|
architecture = 'armv7hf'
|
|
elif target_platform == 'linux/arm64/v8':
|
|
architecture = 'aarch64'
|
|
elif target_platform == 'linux/amd64':
|
|
architecture = 'amd64'
|
|
else:
|
|
click.secho(
|
|
f'Unsupported target platform: {target_platform}',
|
|
fg='red',
|
|
)
|
|
return {}
|
|
|
|
wc_download_url = (
|
|
'https://api.github.com/repos/balena-os/wifi-connect/releases/93025295'
|
|
)
|
|
|
|
try:
|
|
response = requests.get(wc_download_url)
|
|
response.raise_for_status()
|
|
data = response.json()
|
|
assets = [asset['browser_download_url'] for asset in data['assets']]
|
|
|
|
try:
|
|
archive_url = next(
|
|
asset for asset in assets if f'linux-{architecture}' in asset
|
|
)
|
|
except StopIteration:
|
|
click.secho(
|
|
'No wifi-connect release found for this architecture.',
|
|
fg='red',
|
|
)
|
|
archive_url = ''
|
|
|
|
except requests.exceptions.RequestException as e:
|
|
click.secho(f'Failed to get wifi-connect release: {e}', fg='red')
|
|
return {}
|
|
|
|
return {
|
|
'apt_dependencies': [
|
|
'dnsmasq',
|
|
'iw',
|
|
'network-manager',
|
|
'unzip',
|
|
'wget',
|
|
'wireless-tools',
|
|
],
|
|
'archive_url': archive_url,
|
|
}
|