Files
pmomusic/pmoupnp/README_INTROSPECTION.md

5.2 KiB

API d'introspection UPnP

Vue d'ensemble

L'API d'introspection UPnP permet d'explorer et de modifier en temps réel la hiérarchie Device/Service/Action/Variable du serveur UPnP via des endpoints REST.

Architecture

DeviceRegistry (thread_local)
├── DeviceInstanceSet (indexé par nom)
└── Index UDN → nom

UpnpServer trait (pour pmoserver::Server)
├── register_device()  - Enregistre un device
├── device_count()     - Nombre de devices
├── list_devices()     - Liste tous les devices
└── get_device(udn)    - Récupère par UDN

UpnpApiExt trait (pour pmoserver::Server)
└── register_upnp_api() - Monte l'API REST

Utilisation dans PMOMusic

use pmoupnp::{UpnpServer, upnp_api::UpnpApiExt};

let mut server = ServerBuilder::new_configured().build();

// Enregistrer l'API d'introspection
server.register_upnp_api().await;

// Enregistrer un device UPnP
server.register_device(MEDIA_RENDERER.clone()).await?;

Endpoints REST disponibles

Liste tous les devices

GET /api/upnp/devices

Réponse :

{
  "count": 1,
  "devices": [
    {
      "udn": "uuid:f9ef6c21-0ed3-470c-9846-bc1ae85fea62",
      "name": "MediaRenderer",
      "friendly_name": "PMOMusic MediaRenderer",
      "device_type": "urn:schemas-upnp-org:device:MediaRenderer:1",
      "manufacturer": "PMOMusic",
      "model_name": "MediaRenderer",
      "base_url": "http://192.168.1.100:8080",
      "description_url": "http://192.168.1.100:8080/device/uuid:f9ef6c21.../desc.xml"
    }
  ]
}

Détails d'un device

GET /api/upnp/devices/:udn

Réponse :

{
  "udn": "uuid:f9ef6c21-0ed3-470c-9846-bc1ae85fea62",
  "name": "MediaRenderer",
  "friendly_name": "PMOMusic MediaRenderer",
  "device_type": "urn:schemas-upnp-org:device:MediaRenderer:1",
  "manufacturer": "PMOMusic",
  "model_name": "MediaRenderer",
  "base_url": "http://192.168.1.100:8080",
  "description_url": "http://192.168.1.100:8080/device/uuid:f9ef6c21.../desc.xml",
  "services": [
    {
      "name": "AVTransport",
      "service_type": "urn:schemas-upnp-org:service:AVTransport:1",
      "service_id": "urn:upnp-org:serviceId:AVTransport",
      "control_url": "http://192.168.1.100:8080/.../control",
      "event_url": "http://192.168.1.100:8080/.../event",
      "scpd_url": "http://192.168.1.100:8080/.../desc.xml"
    }
  ]
}

Variables d'un service

GET /api/upnp/devices/:udn/services/:service/variables

Réponse :

{
  "udn": "uuid:f9ef6c21-0ed3-470c-9846-bc1ae85fea62",
  "service": "AVTransport",
  "variables": [
    {
      "name": "TransportState",
      "value": "STOPPED",
      "sends_events": true
    },
    {
      "name": "TransportStatus",
      "value": "OK",
      "sends_events": true
    },
    {
      "name": "CurrentTrackURI",
      "value": "",
      "sends_events": true
    }
  ]
}

Développement d'une interface web

L'API REST permet de créer facilement un composant Vue.js pour explorer l'état du serveur UPnP :

<template>
  <div class="upnp-explorer">
    <h2>UPnP Devices</h2>
    <div v-for="device in devices" :key="device.udn">
      <h3>{{ device.friendly_name }}</h3>
      <button @click="loadDeviceDetails(device.udn)">Details</button>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';

const devices = ref([]);

onMounted(async () => {
  const response = await fetch('/api/upnp/devices');
  const data = await response.json();
  devices.value = data.devices;
});

async function loadDeviceDetails(udn) {
  const response = await fetch(`/api/upnp/devices/${udn}`);
  const data = await response.json();
  console.log(data);
}
</script>

Structures de données

DeviceRegistry

Maintient la collection de tous les DeviceInstance avec :

  • Double indexation (par nom et UDN)
  • Méthodes d'introspection
  • Modification des variables d'état

Structures sérialisables

Toutes les structures sont sérialisables en JSON via Serde :

  • DeviceInfo : Informations complètes sur un device
  • ServiceInfo : Informations sur un service
  • ActionInfo : Informations sur une action
  • ArgumentInfo : Informations sur un argument
  • VariableInfo : Informations sur une variable d'état

Fonctions helper

upnp_server::with_devices

Exécute une closure avec accès aux devices :

use pmoupnp::upnp_server::with_devices;

let device_count = with_devices(|devices| devices.len());

upnp_server::get_device_by_udn

Récupère un device par son UDN :

use pmoupnp::upnp_server::get_device_by_udn;

if let Some(device) = get_device_by_udn("uuid:...") {
    println!("Found: {}", device.get_name());
}

Modification des variables (TODO)

L'API pour modifier les variables sera ajoutée ultérieurement via des endpoints POST/PUT :

PUT /api/upnp/devices/:udn/services/:service/variables/:variable
Content-Type: application/json

{
  "value": "PLAYING"
}

Notes d'implémentation

  • Le DeviceRegistry est stocké en thread_local! pour ne pas modifier pmoserver::Server
  • Suit le pattern d'extension utilisé dans PMOMusic (traits UpnpServer et UpnpApiExt)
  • Compatible avec l'architecture existante de pmolog et pmocovers