Controlador, GlobalDatastore y archivos

Esta página describe lo que se sale del esquema « módulos → propiedades → elementos » de las páginas anteriores: los datos del controlador, el módulo central GlobalDatastore y el sistema de archivos del servidor. Un cliente que se limite a mostrar los módulos no los necesita; un cliente que quiera ofrecer lo que propone una página de parámetros globales (configuraciones, drivers INDI, carga del servidor, equipamiento, imágenes) debe tratarlos.

Los datos del controlador (controllerdata)

El controlador es el componente del servidor que carga los módulos y gestiona el servidor INDI embebido. Expone sus propios datos en el dump, bajo la clave controllerdata (ver d), y luego los mantiene al día con mensajes uc.

ClaveContenido
availableconfsConfiguraciones de módulos guardadas: objeto nombre de configuración → lista de {modulelabel, moduletype, profilename}
currentconfNombre de la configuración actual
bannerBanner del servidor (texto libre, opción --banner)
gitVersión del servidor: Gitdate, Githash, Gitmessage, Gittag
librariesBibliotecas de módulos disponibles, un objeto de metadatos por biblioteca
profilesPerfiles disponibles: objeto nombre de clase de módulo → lista de nombres de perfil
indiserver"Y" si el servidor INDI embebido está activado, "N" en caso contrario
indidriversCatálogo de drivers INDI instalados: lista de {binary, family, label, mdpd}
indiactivedriversDrivers INDI actualmente en ejecución
systemwatcherCarga del servidor, ver más abajo
files, foldersCopia de d.files.files y d.files.folders, ver Sistema de archivos
uc: una clave por mensaje, valor reemplazado por completo

Un mensaje uc lleva una sola clave de controllerdata, y su valor reemplaza por completo al anterior (sin fusión). Un cliente que solo lee la primera clave del payload (como hace Rooster) es por tanto correcto mientras el servidor envíe una sola clave por mensaje, que es lo que ocurre hoy.

systemwatcher: carga del servidor

El servidor mide su propia carga a intervalos regulares y la difunde a todos los clientes. El intervalo se ajusta con la opción --systemwatchinterval (segundos, 10 por defecto, 0 lo desactiva). El mensaje es un uc ordinario, y el último valor también está presente en controllerdata.systemwatcher del dump.

{
  "uc-update controller data": {
    "systemwatcher": {
      "cpu": { "load_1m": 10.42, "load_5m": 9.79, "load_15m": 4.51 },
      "ram": { "used_mb": 12194, "total_mb": 31941 },
      "disks": [
        { "device": "/dev/nvme0n1p2", "mountpoint": "/", "used_gb": 789.4, "total_gb": 915.3 }
      ],
      "network": [
        { "iface": "enp4s0", "rx_kbps": 16.27, "tx_kbps": 448.8 }
      ],
      "temperatures": [
        { "type": "Tctl", "temp_c": 75.375 }
      ]
    }
  }
}
CampoSignificado
cpu.load_1m / load_5m / load_15mCarga media del sistema (como /proc/loadavg), no un porcentaje de uso: 1.0 = un núcleo saturado de media
ram.used_mb / total_mbMemoria utilizada (total − disponible) y total, en MB
disks[]Un elemento por dispositivo de almacenamiento montado (/dev/*, excepto loop): device, mountpoint, used_gb, total_gb
network[]Un elemento por interfaz (excepto lo): caudales rx_kbps / tx_kbps medidos entre dos mensajes; la primera medida de una interfaz vale 0
temperatures[]Sensores de hardware del procesador: type, temp_c. La lista puede estar vacía según la máquina (solo se leen los sensores de tipo Intel coretemp y AMD k10temp)
No suponer que los arrays están rellenos

disks, network y sobre todo temperatures pueden estar vacíos. Un cliente debe ocultar la sección correspondiente en lugar de mostrar un array vacío. El protocolo no da el número de núcleos del servidor: un indicador de CPU no puede por tanto ser un verdadero porcentaje, hay que mostrar el valor como una carga.

Configuraciones y ciclo de vida de los módulos

Una configuración es un conjunto con nombre de módulos (biblioteca, etiqueta, perfil) que el servidor puede recargar de una vez. La lista está en controllerdata.availableconfs, la configuración activa en controllerdata.currentconf.

AcciónComandoDetalle
Cargar una configuraciónCLCarga todos los módulos de la configuración
Guardar la configuración actualCSCon el nombre indicado
Cargar un móduloMLBiblioteca, etiqueta, perfil opcional
Descargar un móduloMKPor nombre de módulo

Los módulos efectivamente cargados son los del dump (d.m); aparecen y desaparecen mediante aa y dm. La configuración nunca contiene GlobalDatastore (ver más abajo), que siempre está presente.

Servidor INDI y drivers

Si controllerdata.indiserver vale "Y", el servidor gestiona una instancia INDI embebida. Los comandos YA/YZ/YL/YR/YS la inician, la detienen y gestionan los drivers; controllerdata.indidrivers da el catálogo disponible y controllerdata.indiactivedrivers lo que está en marcha. binary es el valor que se pasa como driver en YL, YR e YS.

El módulo GlobalDatastore

GlobalDatastore es un módulo como los demás en el dump (d.m.GlobalDatastore, con propiedades, elementos, cuadrículas, perfiles), pero su papel es central:

  • lo crea el servidor antes que todos los demás módulos y está siempre presente: MK sobre él se rechaza, y nunca se incluye en una configuración;
  • lleva el referencial compartido del equipamiento, que consultan todos los demás módulos: ópticas, ubicaciones, equipamientos (conjuntos de dispositivos) y servidores INDI.

Sus cuadrículas sirven de fuente a listas de opciones (LOV) del mismo nombre, presentes en d.lovs (optics, locations, equipments, servers) y reconstruidas con cada modificación de la cuadrícula. Los demás módulos las usan así: elegir una óptica rellena la focal y el diámetro, elegir una ubicación rellena latitud, longitud y altitud, elegir un conjunto de equipamiento resuelve los dispositivos (cámara, montura, focuser, rueda de filtros, cámara de guiado, GPS, cúpula, meteo) y el servidor INDI al que conectarse.

Propiedades expuestas:

PropiedadFunción
devicesConjunto de equipamiento y GPS seleccionados (equipments, gps)
devicesactionsBotones: conectar/desconectar los dispositivos, cargar las configuraciones (condevs, discondevs, loadconfs)
serverHost y puerto del servidor INDI (host, port)
serveractionsBotones: conectar/desconectar el servidor INDI (conserv, disconserv)
startupCasillas de inicio automático (indiatstart, devatstart, confsatstart)
equipmentsCuadrícula de los conjuntos de equipamiento
locationsCuadrícula de las ubicaciones (iconos refresh = leer el GPS, add = añadir la fila actual)
opticsCuadrícula de las ópticas
serversCuadrícula de los servidores INDI

Todas sus propiedades se manipulan con los mensajes estándar (SV, SA, GC…, I3/I4 sobre locations); un cliente genérico las muestra como cualquier otro módulo. Rooster las presenta en una pestaña dedicada de su página de parámetros, reteniendo las propiedades que tienen perfil (hasprofile) y agrupándolas por level1/level2.

Sistema de archivos

El servidor publica la lista de los archivos producidos (imágenes, secuencias, archivos) en la carpeta --webroot, sin que el cliente tenga que consultarla. Este mecanismo es independiente de los módulos.

En el dump: d.files

"files": {
  "folders": ["", "/Allsky", "/Sequencer/gam Cyg/LIGHT/Luminance"],
  "files": ["/image1.jpeg", "/rapport.txt"],
  "selectedfolder": "/home/gilles/ostmedia"
}
CampoContenido
foldersTodas las subcarpetas del webroot, recursivamente, rutas relativas al webroot que empiezan por /. La raíz es la cadena vacía "". Sin ordenar.
filesLos archivos de la sola carpeta seleccionada (no recursivo), rutas relativas al webroot que empiezan por /. Todos los archivos, sin filtro de extensión.
selectedfolderLa carpeta seleccionada, como ruta absoluta del sistema de archivos del servidor (y no relativa).

No hay paginación ni límite de tamaño: en un webroot muy lleno, la lista puede ser larga.

Elegir la carpeta: FS

FS designa la carpeta de la que se quiere la lista de archivos. El servidor solo vigila una carpeta a la vez.

La carpeta seleccionada es global en el servidor

No hay carpeta por cliente: un FS cambia la lista de archivos que ven todos los clientes conectados (los eventos siguientes se difunden a todos). Un cliente no debe usarlo para una simple navegación « local » si es posible que haya otros clientes conectados.

El servidor no valida la ruta: una carpeta inexistente devuelve simplemente una lista vacía, sin error.

Actualizaciones: evt

Cuando cambia el contenido de la carpeta seleccionada (archivo creado, eliminado o renombrado), o tras un FS, el servidor envía eventos de primer nivel evt:

{ "evt": "fileadd", "fileevent": ["/Sequencer/gam Cyg/LIGHT/Luminance/img_001.FITS"] }
{ "evt": "filedel", "fileevent": ["/rapport.txt"] }
Valor de evtSignificado
fileaddArchivo(s) aparecido(s) en la carpeta seleccionada
filedelArchivo(s) desaparecido(s) de la carpeta seleccionada
folderadd / folderdelSubcarpeta creada / eliminada en el webroot (misma forma, fileevent contiene las rutas de carpetas)

fileevent es siempre un array; hoy contiene una sola ruta por mensaje (N archivos = N mensajes). Tras un FS, el cliente recibe un filedel por cada archivo de la carpeta anterior y luego un fileadd por cada archivo de la nueva: no hay ningún mensaje que anuncie el nuevo selectedfolder, que solo existe en el dump.

El servidor envía además, en cada pasada, mensajes uc files y folders con las listas completas: un cliente puede por tanto aplicar los eventos evt uno a uno, o simplemente reemplazar sus listas con esos uc.

Trampa: evt empieza por ev

La regla habitual es comparar los 1 o 2 primeros caracteres de la clave. Pero evt empieza por ev, el tipo de las actualizaciones de elemento con metadatos, cuyo payload es un objeto y no una cadena. Un cliente que despacha por prefijo debe comprobar la igualdad exacta con evt antes de comprobar ev; de lo contrario tomará un evento de archivo por una actualización de elemento.

Construir la URL de un archivo

Las rutas de files son relativas al webroot y empiezan por /. La URL de un archivo es la URL base de los medios del servidor (http(s)://hostname/ostmedia/, ver la nota « URLs media » del Modelo de datos) seguida de la ruta. Cuidado con el / inicial: concatenarlo a una base que ya termina en / da un doble //.

Lo que no hace el evento

El servidor detecta el alta, la baja y el cambio de nombre de archivos, no la modificación del contenido de un archivo existente: una imagen reescrita con el mismo nombre no produce ningún evento. Es el caso de las imágenes de previsualización de los módulos, cuya URL permanece idéntica en cada toma: un cliente debe añadir un parámetro de cache-busting (?t= + marca de tiempo) al recargar una imagen tras una actualización de su propiedad.