Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f1bfab969c |
@@ -1,5 +1,21 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [0.9.13] – 2026-05-20
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- **Self-Update war in 0.9.12 kaputt (wichtig):** Der In-App-Updater ersetzte
|
||||||
|
nur `kobrax_moonraker_bridge.py`, aber seit 0.9.12 importiert diese Datei das
|
||||||
|
ausgelagerte `_web_assets.py` (gebündeltes Frontend). Ein Update auf 0.9.12
|
||||||
|
crashte daher mit `ModuleNotFoundError: No module named '_web_assets'` und die
|
||||||
|
Bridge kam nicht wieder hoch. Der Updater lädt jetzt **alle** Bridge-Module
|
||||||
|
(Hauptdatei + `_web_assets.py` + Client + Loader) erst vollständig herunter
|
||||||
|
und ersetzt sie dann atomar — und verweigert das Self-Update im Binary-Modus
|
||||||
|
(stattdessen neue Binary/neues Docker-Image laden).
|
||||||
|
|
||||||
|
> Falls du nach dem Update auf 0.9.12 hängengeblieben bist: einmalig das
|
||||||
|
> Docker-Image neu bauen/deployen oder die 0.9.13-Binary holen, danach
|
||||||
|
> funktioniert das Self-Update wieder.
|
||||||
|
|
||||||
## [0.9.12] – 2026-05-20
|
## [0.9.12] – 2026-05-20
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|||||||
15
CHANGELOG.md
15
CHANGELOG.md
@@ -1,5 +1,20 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [0.9.13] – 2026-05-20
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- **Self-update was broken for 0.9.12 (important):** the in-app updater only
|
||||||
|
replaced `kobrax_moonraker_bridge.py`, but since 0.9.12 that file imports the
|
||||||
|
extracted `_web_assets.py` (bundled frontend). Updating to 0.9.12 therefore
|
||||||
|
crashed with `ModuleNotFoundError: No module named '_web_assets'` and the
|
||||||
|
bridge wouldn't come back up. The updater now downloads **all** bridge modules
|
||||||
|
(main file + `_web_assets.py` + client + loaders), fully, then swaps them
|
||||||
|
atomically — and refuses to self-update in binary mode (use the new
|
||||||
|
binary/Docker image instead).
|
||||||
|
|
||||||
|
> If you got stuck on 0.9.12 after pressing update: rebuild/redeploy the Docker
|
||||||
|
> image or grab the 0.9.13 binary once, then self-update works again.
|
||||||
|
|
||||||
## [0.9.12] – 2026-05-20
|
## [0.9.12] – 2026-05-20
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|||||||
@@ -2877,26 +2877,51 @@ class KobraXBridge:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return web.json_response({"error": str(e)}, status=502)
|
return web.json_response({"error": str(e)}, status=502)
|
||||||
|
|
||||||
|
# Bridge-Python-Module, die das Self-Update mitziehen muss. Die Hauptdatei
|
||||||
|
# importiert _web_assets (gebündeltes Frontend) etc. – wird nur die Hauptdatei
|
||||||
|
# ersetzt, crasht die neue Version mit ModuleNotFoundError. Daher alle laden.
|
||||||
|
_UPDATE_FILES = [
|
||||||
|
"kobrax_moonraker_bridge.py",
|
||||||
|
"_web_assets.py",
|
||||||
|
"kobrax_client.py",
|
||||||
|
"config_loader.py",
|
||||||
|
"env_loader.py",
|
||||||
|
]
|
||||||
|
|
||||||
async def handle_api_update_apply(self, request):
|
async def handle_api_update_apply(self, request):
|
||||||
data = await request.json()
|
data = await request.json()
|
||||||
download_url = data.get("download_url", "")
|
|
||||||
new_tag = data.get("tag", "")
|
new_tag = data.get("tag", "")
|
||||||
if not download_url:
|
if getattr(sys, "frozen", False):
|
||||||
return web.json_response({"error": "download_url fehlt"}, status=400)
|
return web.json_response(
|
||||||
script_path = pathlib.Path(sys.executable if getattr(sys, "frozen", False) else __file__).resolve()
|
{"error": "Self-Update wird im Binary-Modus nicht unterstützt – "
|
||||||
|
"bitte neue Binary/Docker-Image laden."}, status=400)
|
||||||
|
if not new_tag:
|
||||||
|
return web.json_response({"error": "tag fehlt"}, status=400)
|
||||||
|
|
||||||
|
app_dir = pathlib.Path(__file__).resolve().parent
|
||||||
try:
|
try:
|
||||||
|
# Phase 1: ALLE Dateien herunterladen (in .new), nichts ersetzen.
|
||||||
|
downloaded: list[tuple[pathlib.Path, bytes]] = []
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
async with session.get(download_url, timeout=aiohttp.ClientTimeout(total=30)) as resp:
|
for fname in self._UPDATE_FILES:
|
||||||
|
url = f"{self.GITEA_RAW_BASE}/{new_tag}/{fname}"
|
||||||
|
async with session.get(url, timeout=aiohttp.ClientTimeout(total=30)) as resp:
|
||||||
if resp.status != 200:
|
if resp.status != 200:
|
||||||
return web.json_response({"error": f"Download HTTP {resp.status}"}, status=502)
|
# _web_assets.py o.ä. existiert evtl. in älteren Tags nicht –
|
||||||
content = await resp.read()
|
# Hauptdatei ist Pflicht, optionale dürfen fehlen.
|
||||||
# Atomisch ersetzen
|
if fname == "kobrax_moonraker_bridge.py":
|
||||||
tmp = script_path.with_suffix(".py.new")
|
return web.json_response(
|
||||||
|
{"error": f"Download {fname}: HTTP {resp.status}"}, status=502)
|
||||||
|
log.warning(f"Update: {fname} nicht im Release ({resp.status}) – übersprungen")
|
||||||
|
continue
|
||||||
|
downloaded.append((app_dir / fname, await resp.read()))
|
||||||
|
# Phase 2: atomar ersetzen (erst nach komplettem, erfolgreichem Download)
|
||||||
|
for path, content in downloaded:
|
||||||
|
tmp = path.with_suffix(path.suffix + ".new")
|
||||||
tmp.write_bytes(content)
|
tmp.write_bytes(content)
|
||||||
os.replace(tmp, script_path)
|
os.replace(tmp, path)
|
||||||
if new_tag:
|
|
||||||
self._write_version(new_tag.lstrip("v"))
|
self._write_version(new_tag.lstrip("v"))
|
||||||
log.info(f"Update auf {new_tag} installiert, starte neu …")
|
log.info(f"Update auf {new_tag} installiert ({len(downloaded)} Dateien), starte neu …")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return web.json_response({"error": str(e)}, status=502)
|
return web.json_response({"error": str(e)}, status=502)
|
||||||
response = web.json_response({"status": "updating"})
|
response = web.json_response({"status": "updating"})
|
||||||
|
|||||||
Reference in New Issue
Block a user