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 {