mirror of https://git.48k.eu/ogclient
kiosk: obtain os probe data from ogClient
Define a kiosk event "refresh" to send configuration data from ogClient to Kiosk. Send the OS list after an ogClient refresh operation. Reload widgets in Kiosk when a refresh event is received.ogkiosk
parent
39c97fc1bc
commit
213c9f47a3
|
@ -10,6 +10,7 @@ from PyQt6.QtWidgets import (
|
|||
)
|
||||
from PyQt6.QtCore import Qt, QSize, pyqtSignal
|
||||
from PyQt6.QtGui import QPixmap, QIcon
|
||||
from src.utils.probe import OSFamily
|
||||
from src.kiosk.config import *
|
||||
from src.kiosk.theme import *
|
||||
|
||||
|
@ -25,7 +26,6 @@ class BootView(QWidget):
|
|||
super().__init__()
|
||||
|
||||
self.checked_os = None
|
||||
probe_partitions()
|
||||
|
||||
self.layout = QVBoxLayout()
|
||||
self.layout.setSpacing(10)
|
||||
|
@ -67,9 +67,9 @@ class BootView(QWidget):
|
|||
button.setStyleSheet(f'height: {BUTTON_HEIGHT}px; width: {BUTTON_WIDTH}px;')
|
||||
button.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextUnderIcon)
|
||||
button.setCheckable(True)
|
||||
if part_data['os'] == OSFamily.WINDOWS:
|
||||
if part_data['os'] == OSFamily.WINDOWS.name:
|
||||
button.setIcon(win_icon)
|
||||
elif part_data['os'] == OSFamily.LINUX:
|
||||
elif part_data['os'] == OSFamily.LINUX.name:
|
||||
button.setIcon(linux_icon)
|
||||
button.setIconSize(QSize(BUTTON_ICON_SIZE, BUTTON_ICON_SIZE))
|
||||
button.toggled.connect(lambda checked, b=button: self.on_part_button_checked(checked, b))
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
# Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
from src.utils.probe import os_probe, get_os_family, OSFamily
|
||||
from src.utils.fs import mount_mkdir, umount
|
||||
from PyQt6.QtGui import QColor
|
||||
from src.utils.disk import *
|
||||
from src.utils.net import *
|
||||
|
@ -16,39 +14,13 @@ import os
|
|||
|
||||
config_data = {}
|
||||
|
||||
def update_config(new_config):
|
||||
for k in new_config:
|
||||
config_data[k] = new_config[k]
|
||||
|
||||
def get_boot_os_list():
|
||||
return config_data.get('os_list', [])
|
||||
|
||||
def probe_partitions():
|
||||
os_list = []
|
||||
for disknum, disk in enumerate(get_disks(), start=1):
|
||||
try:
|
||||
partitions = get_partition_data(device=f'/dev/{disk}')
|
||||
except Exception as e:
|
||||
continue
|
||||
|
||||
for pa in partitions:
|
||||
partnum = pa.partno + 1
|
||||
mountpoint = pa.padev.replace('dev', 'mnt')
|
||||
if mount_mkdir(pa.padev, mountpoint):
|
||||
try:
|
||||
os_family = get_os_family(mountpoint)
|
||||
if os_family == OSFamily.UNKNOWN:
|
||||
continue
|
||||
os_name = os_probe(mountpoint)
|
||||
os_data = {
|
||||
'name': os_name,
|
||||
'partition': partnum,
|
||||
'disk': disknum,
|
||||
'os': os_family,
|
||||
'image': ''
|
||||
}
|
||||
os_list.append(os_data)
|
||||
finally:
|
||||
umount(mountpoint)
|
||||
config_data['os_list'] = os_list
|
||||
|
||||
def get_main_color_theme():
|
||||
color_values = config_data.get('color_theme', [49, 69, 106])
|
||||
return QColor(*color_values)
|
||||
|
|
|
@ -51,7 +51,8 @@ class Kiosk(QMainWindow):
|
|||
self.main_content.setLayout(QVBoxLayout())
|
||||
layout.addWidget(self.main_content)
|
||||
|
||||
self.reload_theme()
|
||||
self.instance_sidepanel()
|
||||
self.side_panel.request_widget_change(ViewType.BOOT_OS)
|
||||
|
||||
def closeEvent(self, event):
|
||||
if self.socket_notifier:
|
||||
|
@ -82,6 +83,8 @@ class Kiosk(QMainWindow):
|
|||
status = payload.get('status', 'idle')
|
||||
self.apply_busy_mode_configuration(status)
|
||||
elif payload.get('command') == 'refresh':
|
||||
new_configuration = payload.get('config', {})
|
||||
update_config(new_configuration)
|
||||
self.reload_theme()
|
||||
elif payload.get('command') == 'close':
|
||||
self.close()
|
||||
|
@ -90,24 +93,23 @@ class Kiosk(QMainWindow):
|
|||
except json.JSONDecodeError as e:
|
||||
logging.error(f'Failed to decode JSON: {e}')
|
||||
|
||||
def reload_theme(self):
|
||||
# Floating side panel
|
||||
if self.side_panel:
|
||||
self.side_panel.setParent(None)
|
||||
self.side_panel.deleteLater()
|
||||
def instance_sidepanel(self):
|
||||
self.side_panel = SidePanel()
|
||||
self.side_panel.setParent(self)
|
||||
self.side_panel.setFixedWidth(SIDE_PANEL_WIDTH)
|
||||
self.side_panel.panel_hidden = True
|
||||
self.side_panel.setGeometry(-SIDE_PANEL_WIDTH, 0, SIDE_PANEL_WIDTH, self.height())
|
||||
self.side_panel.widget_change_requested.connect(self.update_view)
|
||||
self.side_panel.emit_default_widget()
|
||||
self.side_panel.setVisible(True)
|
||||
self.side_panel.raise_()
|
||||
|
||||
self.animation = QPropertyAnimation(self.side_panel, b'geometry')
|
||||
self.animation.setDuration(200)
|
||||
|
||||
def reload_theme(self):
|
||||
self.side_panel.reload_theme()
|
||||
if self.side_panel.last_widget == ViewType.BOOT_OS:
|
||||
self.side_panel.request_widget_change(ViewType.BOOT_OS)
|
||||
|
||||
def apply_busy_mode_configuration(self, status):
|
||||
if get_status() == status:
|
||||
return
|
||||
|
|
|
@ -56,6 +56,8 @@ class SidePanel(QFrame):
|
|||
super().__init__()
|
||||
|
||||
self.panel_hidden = False
|
||||
self.last_widget = ViewType.BOOT_OS
|
||||
self.button_map = {}
|
||||
|
||||
self.setFrameStyle(QFrame.Shape.StyledPanel | QFrame.Shadow.Plain)
|
||||
|
||||
|
@ -71,11 +73,12 @@ class SidePanel(QFrame):
|
|||
layout.addWidget(button)
|
||||
button.clicked.connect(lambda _, view=view_type: self.request_widget_change(view))
|
||||
|
||||
self.button_map[view_type] = button
|
||||
|
||||
def reload_theme(self):
|
||||
for view_type, button in self.button_map.items():
|
||||
button.setIcon(view_type.get_view_icon())
|
||||
|
||||
def request_widget_change(self, view_type):
|
||||
self.last_widget = view_type
|
||||
self.widget_change_requested.emit(view_type.get_widget_instance())
|
||||
|
||||
def emit_default_widget(self):
|
||||
self.request_widget_change(ViewType.BOOT_OS)
|
||||
|
||||
def emit_monitor_widget(self):
|
||||
self.request_widget_change(ViewType.SYSTEM_MONITOR)
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
#
|
||||
# Copyright (C) 2020-2025 Soleta Networks <info@soleta.eu>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the
|
||||
# Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
kiosk_config = {}
|
||||
|
||||
def update_kiosk_config(refresh_payload):
|
||||
from src.utils.probe import OSFamily
|
||||
os_list = []
|
||||
for part_setup in refresh_payload['partition_setup']:
|
||||
if part_setup['os_family'] == OSFamily.UNKNOWN.name:
|
||||
del part_setup['os_family']
|
||||
continue
|
||||
os_data = {
|
||||
'name': part_setup['os'],
|
||||
'partition': int(part_setup['partition']),
|
||||
'disk': int(part_setup['disk']),
|
||||
'os': part_setup['os_family'],
|
||||
'image': ''
|
||||
}
|
||||
del part_setup['os_family']
|
||||
os_list.append(os_data)
|
||||
kiosk_config['os_list'] = os_list
|
|
@ -23,6 +23,7 @@ from src.live.partcodes import GUID_MAP
|
|||
from src.live.parttypes import get_parttype
|
||||
|
||||
from src.utils.image import *
|
||||
from src.live.kiosk import *
|
||||
from src.utils.postinstall import configure_os
|
||||
from src.utils.net import *
|
||||
from src.utils.menu import generate_menu
|
||||
|
@ -83,9 +84,12 @@ class OgLiveOperations:
|
|||
|
||||
if mount_mkdir(pa.padev, target):
|
||||
part_setup['os'] = ''
|
||||
part_setup['os_family'] = OSFamily.UNKNOWN.name
|
||||
if part_setup['disk'] == '1':
|
||||
probe_result = os_probe(target)
|
||||
part_setup['os'] = probe_result
|
||||
os_family = get_os_family(target)
|
||||
part_setup['os_family'] = os_family.name
|
||||
|
||||
total, used, free = shutil.disk_usage(target)
|
||||
part_setup['used_size'] = used
|
||||
|
@ -93,6 +97,7 @@ class OgLiveOperations:
|
|||
umount(target)
|
||||
else:
|
||||
part_setup['os'] = ''
|
||||
part_setup['os_family'] = OSFamily.UNKNOWN.name
|
||||
part_setup['used_size'] = 0
|
||||
part_setup['free_size'] = 0
|
||||
|
||||
|
@ -861,6 +866,7 @@ class OgLiveOperations:
|
|||
if boot_entry_data:
|
||||
json_body['efi'] = boot_entry_data
|
||||
|
||||
update_kiosk_config(json_body)
|
||||
generate_menu(json_body['partition_setup'])
|
||||
generate_cache_txt()
|
||||
self._restartBrowser(self._url)
|
||||
|
|
|
@ -16,6 +16,7 @@ import logging
|
|||
from io import StringIO
|
||||
|
||||
from src.restRequest import *
|
||||
from src.live.kiosk import *
|
||||
from src.ogRest import *
|
||||
from src.log import OgError
|
||||
from enum import Enum
|
||||
|
@ -159,6 +160,12 @@ class ogClient:
|
|||
except Exception as e:
|
||||
logging.error(f"Unexpected error in send_kiosk_event: {e}")
|
||||
|
||||
def send_kiosk_refresh(self):
|
||||
self.send_kiosk_event({
|
||||
'command': 'refresh',
|
||||
'config': kiosk_config
|
||||
})
|
||||
|
||||
def cleanup(self):
|
||||
self.data = ""
|
||||
self.content_len = 0
|
||||
|
|
|
@ -176,6 +176,7 @@ class ogThread():
|
|||
|
||||
response = restResponse(ogResponses.OK, json_body, seq=client.seq)
|
||||
client.send(response.get())
|
||||
client.send_kiosk_refresh()
|
||||
ogRest.set_state(ThreadState.IDLE, client)
|
||||
|
||||
def image_restore_local(client, request, ogRest):
|
||||
|
@ -200,6 +201,7 @@ class ogThread():
|
|||
|
||||
response = restResponse(ogResponses.OK, json_body, seq=client.seq)
|
||||
client.send(response.get())
|
||||
client.send_kiosk_refresh()
|
||||
ogRest.set_state(ThreadState.IDLE, client)
|
||||
|
||||
def image_create(client, request, ogRest):
|
||||
|
@ -271,6 +273,7 @@ class ogThread():
|
|||
|
||||
response = restResponse(ogResponses.OK, json_body, seq=client.seq)
|
||||
client.send(response.get())
|
||||
client.send_kiosk_refresh()
|
||||
ogRest.set_state(ThreadState.IDLE, client, update_kiosk=False)
|
||||
|
||||
class ogResponses(Enum):
|
||||
|
|
Loading…
Reference in New Issue