homebridge-prometheus-exporter/src/platform.ts

118 lines
4.3 KiB
TypeScript
Raw Normal View History

2022-11-06 13:50:39 +01:00
import { API, Logger, PlatformConfig, IndependentPlatformPlugin } from 'homebridge'
2022-11-06 13:04:30 +01:00
2022-11-06 13:50:39 +01:00
import { Metric, aggregate } from './metrics'
import { discover } from './discovery/hap_node_js_client'
import { serve } from './http/fastify'
import { HttpServerController } from './http/api'
2022-11-07 20:49:11 +01:00
import { MetricsRenderer } from './prometheus'
2022-11-06 13:04:30 +01:00
2022-11-06 13:50:39 +01:00
export class PrometheusExporterPlatform implements IndependentPlatformPlugin {
private metrics: Metric[] = []
private metricsDiscovered = false
private http: HttpServerController | undefined = undefined
2022-11-06 13:04:30 +01:00
2022-11-06 13:50:39 +01:00
constructor(public readonly log: Logger, public readonly config: PlatformConfig, public readonly api: API) {
this.log.debug('Initializing platform %s', this.config.platform)
2022-11-06 13:04:30 +01:00
2022-11-06 13:50:39 +01:00
this.configure()
2022-11-06 13:04:30 +01:00
2022-11-06 13:50:39 +01:00
this.api.on('shutdown', () => {
this.log.debug('Shutting down %s', this.config.platform)
if (this.http) {
this.http.shutdown()
}
})
2022-11-06 13:04:30 +01:00
2022-11-06 13:50:39 +01:00
this.startHttpServer()
2022-11-06 13:04:30 +01:00
2022-11-06 13:50:39 +01:00
this.api.on('didFinishLaunching', () => {
this.log.debug('Finished launching %s', this.config.platform)
this.startHapDiscovery()
})
}
2022-11-06 13:04:30 +01:00
2022-11-06 13:50:39 +01:00
private configure(): void {
if (this.config.pin !== 'string' || !this.config.pin.match(/^\d{3}-\d{2}-\d{3}$/)) {
this.log.error('"pin" must be defined in config and match format 000-00-000')
}
2022-11-06 13:04:30 +01:00
2022-11-06 13:50:39 +01:00
this.config.debug = this.config.debug ?? false
this.config.probe_port = this.config.probe_port ?? 36123
this.config.refresh_interval = this.config.refresh_interval || 60
this.config.request_timeout = this.config.request_timeout || 10
this.config.discovery_timeout = this.config.discovery_timeout || 20
2022-11-06 13:04:30 +01:00
2022-11-06 13:50:39 +01:00
this.log.debug('Configuration materialized: %o', this.config)
}
2022-11-06 13:04:30 +01:00
2022-11-06 13:50:39 +01:00
private startHttpServer(): void {
this.log.debug('Starting probe HTTP server on port %d', this.config.probe_port)
const contentTypeHeader = { 'Content-Type': 'text/plain; charset=UTF-8' }
serve({
port: this.config.probe_port,
logger: this.log,
requestInterceptor: () => {
if (!this.metricsDiscovered) {
return {
statusCode: 503,
headers: { ...contentTypeHeader, 'Retry-After': '10' },
body: 'Discovery pending',
}
}
},
2022-11-07 20:53:38 +01:00
metricsController: () => {
2022-11-07 20:49:11 +01:00
const renderer = new MetricsRenderer('homebridge')
2022-11-07 20:53:38 +01:00
const metrics = this.metrics.map((metric) => renderer.render(metric)).join('\n')
2022-11-06 13:50:39 +01:00
return {
statusCode: 200,
headers: contentTypeHeader,
body: metrics,
}
},
notFoundController: () => ({
statusCode: 404,
headers: contentTypeHeader,
2022-11-07 20:53:38 +01:00
body: 'Not found. Try /metrics',
2022-11-06 13:50:39 +01:00
}),
2022-11-07 20:53:38 +01:00
errorController: (e) => {
this.log.error('HTTP request error: %o', e)
return {
statusCode: 500,
headers: contentTypeHeader,
body: 'Server error',
}
},
2022-11-06 13:50:39 +01:00
})
.then((http) => {
this.log.debug('HTTP server started on port %d', this.config.probe_port)
this.http = http
})
.catch((e) => {
this.log.error('Failed to start probe HTTP server on port %d: %o', this.config.probe_port, e)
})
}
2022-11-06 13:04:30 +01:00
2022-11-06 13:50:39 +01:00
private startHapDiscovery(): void {
this.log.debug('Starting HAP discovery')
discover({
logger: this.log,
refreshInterval: this.config.refresh_interval,
discoveryTimeout: this.config.discovery_timeout,
requestTimeout: this.config.request_timeout,
pin: this.config.pin,
debug: this.config.debug,
})
.then((devices) => {
2022-11-07 20:49:11 +01:00
this.metrics = aggregate(devices, new Date())
2022-11-06 13:50:39 +01:00
this.metricsDiscovered = true
this.log.debug('HAP discovery completed, %d metrics discovered', this.metrics.length)
2022-11-07 19:30:55 +01:00
this.startHapDiscovery()
2022-11-06 13:50:39 +01:00
})
.catch((e) => {
this.log.error('HAP discovery error', e)
})
2022-11-06 13:04:30 +01:00
}
}