Files
adam-acs/app/controllers/references_controller.ts
T
Kevin L'Hereec e857b4fbe7 feat: reference providers system with Wassup integration
- Pluggable multi-provider architecture (ReferenceEngine)
- Wassup provider implementation (HTTP GET + X_WASSUP_USER_IP)
- Auto-resolve references on Inform (BOOT/BOOTSTRAP events)
- References displayed in device Identity card
- REST API: GET/POST references per device
- Config via config/references.json
- Fix event extraction for single EventStruct and numeric EventCodes
- Mock Wassup provisioned by home-device-simulator on device creation
2026-06-02 15:52:16 +02:00

88 lines
3.2 KiB
TypeScript

import type { HttpContext } from '@adonisjs/core/http'
import DeviceModel from '#models/device'
import { getReferenceEngine } from '../services/references/reference_engine.js'
export default class ReferencesController {
/**
* GET /api/v1/devices/:identifier/references
*/
async index({ params, response }: HttpContext) {
const device = await DeviceModel.findByIdentifier(params.identifier)
if (!device) {
return response.status(404).json({ message: 'Device not found' })
}
return response.json({ references: device.references || [] })
}
/**
* GET /api/v1/devices/:identifier/references/:provider
*/
async show({ params, response }: HttpContext) {
const device = await DeviceModel.findByIdentifier(params.identifier)
if (!device) {
return response.status(404).json({ message: 'Device not found' })
}
const ref = (device.references || []).find((r: any) => r.provider === params.provider)
if (!ref) {
return response.status(404).json({ message: `No reference from provider '${params.provider}'` })
}
return response.json(ref)
}
/**
* POST /api/v1/devices/:identifier/references/resolve
* Trigger resolution for all applicable providers.
*/
async resolveAll({ params, response }: HttpContext) {
const device = await DeviceModel.findByIdentifier(params.identifier)
if (!device) {
return response.status(404).json({ message: 'Device not found' })
}
const engine = getReferenceEngine()
const context = { events: ['MANUAL'], remoteIp: '', headers: {} }
// For manual resolution, use all providers regardless of trigger
const results = await engine.resolveAll(device, { ...context, events: ['0 BOOTSTRAP'] })
if (results.length > 0) {
// Merge with existing references (replace by provider name)
const existing = (device.references || []).filter(
(r: any) => !results.some((nr) => nr.provider === r.provider)
)
const merged = [...existing, ...results]
await DeviceModel.updateOne({ identifier: params.identifier }, { $set: { references: merged, updatedAt: new Date() } })
}
return response.json({ resolved: results.length, references: results })
}
/**
* POST /api/v1/devices/:identifier/references/resolve/:provider
* Trigger resolution for a single provider.
*/
async resolveOne({ params, response }: HttpContext) {
const device = await DeviceModel.findByIdentifier(params.identifier)
if (!device) {
return response.status(404).json({ message: 'Device not found' })
}
const engine = getReferenceEngine()
const context = { events: ['0 BOOTSTRAP'], remoteIp: '', headers: {} }
const result = await engine.resolveOne(params.provider, device, context)
if (!result) {
return response.status(404).json({ message: `Provider '${params.provider}' not found or cannot resolve` })
}
// Merge into device references
const existing = (device.references || []).filter((r: any) => r.provider !== params.provider)
await DeviceModel.updateOne(
{ identifier: params.identifier },
{ $set: { references: [...existing, result], updatedAt: new Date() } }
)
return response.json(result)
}
}