diff --git a/control/frontend/src/lib/components/DisplayGroupObject.svelte b/control/frontend/src/lib/components/DisplayGroupObject.svelte
index cc0c6e0..3d54ed7 100644
--- a/control/frontend/src/lib/components/DisplayGroupObject.svelte
+++ b/control/frontend/src/lib/components/DisplayGroupObject.svelte
@@ -26,7 +26,7 @@
close_pinned_display
}: {
display_id_group: DisplayIdGroup;
- get_display_menu_options: (display_id: string) => MenuOption[];
+ get_display_menu_options: (display_id: string, display_version: string|undefined) => MenuOption[];
close_pinned_display: () => void;
} = $props();
diff --git a/control/frontend/src/lib/components/DisplayObject.svelte b/control/frontend/src/lib/components/DisplayObject.svelte
index 66b8af0..4a90be2 100755
--- a/control/frontend/src/lib/components/DisplayObject.svelte
+++ b/control/frontend/src/lib/components/DisplayObject.svelte
@@ -20,7 +20,7 @@
close_pinned_display
}: {
display_id_object: DisplayIdObject;
- get_display_menu_options: (display_id: string) => MenuOption[];
+ get_display_menu_options: (display_id: string, display_version: string|undefined) => MenuOption[];
close_pinned_display: () => void;
} = $props();
@@ -136,7 +136,7 @@
click_function={(e) => {
e.stopPropagation();
}}
- menu_options={get_display_menu_options(display_id_object.id)}
+ menu_options={get_display_menu_options(display_id_object.id, $display?.version)}
>
diff --git a/control/frontend/src/lib/ts/api_handler.ts b/control/frontend/src/lib/ts/api_handler.ts
index a282ab5..d567273 100755
--- a/control/frontend/src/lib/ts/api_handler.ts
+++ b/control/frontend/src/lib/ts/api_handler.ts
@@ -186,15 +186,21 @@ export async function get_thumbnail_blob(ip: string, path_to_file: string): Prom
return raw_response.blob;
}
-export async function ping_ip(ip: string): Promise {
+export async function ping_ip(ip: string): Promise<{ status: DisplayStatus; version?: string }> {
const raw_response = await request_control(`/ping?ip=${ip}`, { method: 'GET' });
- if (!raw_response.ok || !raw_response.json) return null;
+ if (!raw_response.ok || !raw_response.json) return { status: null };
- const status = raw_response.json.status;
- if (typeof status === 'string') {
- return to_display_status(status);
+ const raw_status = raw_response.json.status;
+ if (typeof raw_status === 'string') {
+ const status = to_display_status(raw_status);
+ const version = raw_response.json.version;
+ if (typeof version === 'string') {
+ return { status, version };
+ } else {
+ return { status };
+ }
}
- return null;
+ return { status: null };
}
async function request_display(
diff --git a/control/frontend/src/lib/ts/main.ts b/control/frontend/src/lib/ts/main.ts
index 5d17d2f..ab6a761 100755
--- a/control/frontend/src/lib/ts/main.ts
+++ b/control/frontend/src/lib/ts/main.ts
@@ -40,22 +40,26 @@ async function update_all_display_status(only_loading_displays: boolean) {
}
export async function update_display_status(display: Display): Promise {
- const new_status = await ping_ip(display.ip);
- if (new_status === null && display.status !== null) return null;
- if (new_status !== display.status) {
+ const resp = await ping_ip(display.ip);
+ if (resp.version && display.version !== resp.version) {
+ display.version = resp.version;
+ await db.displays.put(display); // save
+ }
+ if (resp.status === null && display.status !== null) return null;
+ if (resp.status !== display.status) {
// status change
- if (new_status === 'app_offline') {
+ if (resp.status === 'app_offline') {
loading_display_ids.push(display.id);
} else {
remove_display_from_loading_displays(display.id);
- if (new_status === 'app_online') {
+ if (resp.status === 'app_online') {
on_display_start(display);
}
}
- display.status = new_status;
+ display.status = resp.status;
await db.displays.put(display); // save
}
- return new_status;
+ return resp.status;
}
export function remove_display_from_loading_displays(display_id: string) {
diff --git a/control/frontend/src/lib/ts/types.ts b/control/frontend/src/lib/ts/types.ts
index c892b86..caba910 100755
--- a/control/frontend/src/lib/ts/types.ts
+++ b/control/frontend/src/lib/ts/types.ts
@@ -96,6 +96,7 @@ export type Display = {
group_id: string;
name: string;
status: DisplayStatus;
+ version?: string;
};
export type DisplayGroup = {
diff --git a/control/frontend/src/routes/DisplayView.svelte b/control/frontend/src/routes/DisplayView.svelte
index 4b1d86e..d37356c 100755
--- a/control/frontend/src/routes/DisplayView.svelte
+++ b/control/frontend/src/routes/DisplayView.svelte
@@ -21,7 +21,7 @@
import { type Display, type DisplayGroup, type MenuOption } from '$lib/ts/types';
import Button from '$lib/components/Button.svelte';
import OnlineState from '../lib/components/OnlineState.svelte';
- import { Menu, Pencil, PinOff, Trash2, VideoOff, ZoomIn, ZoomOut } from 'lucide-svelte';
+ import { History, Menu, Pencil, PinOff, Trash2, VideoOff, ZoomIn, ZoomOut } from 'lucide-svelte';
import { selected_display_ids } from '$lib/ts/stores/select';
import { dragHandleZone } from 'svelte-dnd-action';
import DisplayGroupObject from '../lib/components/DisplayGroupObject.svelte';
@@ -68,8 +68,13 @@
pinned_pane_size = 0;
}
- function get_display_menu_options(display_id: string): MenuOption[] {
+ function get_display_menu_options(display_id: string, display_version: string|undefined): MenuOption[] {
return [
+ {
+ icon: History,
+ name: display_version ?? "Version unbekannt",
+ disabled: true,
+ },
{
icon: Pencil,
name: 'Bildschirm bearbeiten',
@@ -165,7 +170,7 @@
click_function={(e) => {
e.stopPropagation();
}}
- menu_options={get_display_menu_options($pinned_display_id)}
+ menu_options={get_display_menu_options($pinned_display_id, $pinned_display?.version)}
>
diff --git a/control/main.go b/control/main.go
index 261e3c7..c72591c 100644
--- a/control/main.go
+++ b/control/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "encoding/json"
"log/slog"
"net"
"net/http"
@@ -83,18 +84,40 @@ func pingRoute(ctx echo.Context) error {
return ctx.JSON(http.StatusOK, PingResponse{Status: "host_offline"})
}
- conn, err := net.DialTimeout("tcp", ip+":1323", 5*time.Second)
+ client := http.Client{
+ Timeout: 5 * time.Second,
+ }
+
+ resp, err := client.Get("http://" + ip + ":1323/api/ping")
if err != nil {
return ctx.JSON(http.StatusOK, PingResponse{Status: "app_offline"})
}
- conn.Close()
+ defer resp.Body.Close()
+ if resp.StatusCode != http.StatusOK {
+ return ctx.JSON(http.StatusOK, PingResponse{Status: "app_offline"})
+ }
- return ctx.JSON(http.StatusOK, PingResponse{Status: "app_online"})
+ var appPing AppPingResponse
+ if err := json.NewDecoder(resp.Body).Decode(&appPing); err != nil {
+ return ctx.JSON(http.StatusOK, PingResponse{
+ Status: "app_offline",
+ })
+ }
+
+ return ctx.JSON(http.StatusOK, PingResponse{
+ Status: "app_online",
+ Version: appPing.Version,
+ })
+}
+
+type AppPingResponse struct {
+ Version string `json:"version"`
}
type PingResponse struct {
- Status string `json:"status"`
- Error string `json:"error"`
+ Status string `json:"status"`
+ Version string `json:"version"`
+ Error string `json:"error"`
}
type WakeOnLanRequest struct {