diff --git a/app/src/handlers/demo-plc.ts b/app/src/handlers/demo-plc.ts index 968f6ef..ea44cba 100644 --- a/app/src/handlers/demo-plc.ts +++ b/app/src/handlers/demo-plc.ts @@ -12,24 +12,11 @@ type DemoPlcPayload = { value: number } -type DemoPlcMetric = DemoPlcPayload & { +type DemoPlcMetric = { edge: string timestamp: number -} - -function isDemoPlcPayload(value: unknown): value is DemoPlcPayload { - if (!value || typeof value !== 'object') { - return false - } - - const candidate = value as Partial - - return ( - typeof candidate.tag === 'string' && - candidate.tag.length > 0 && - typeof candidate.value === 'number' && - Number.isFinite(candidate.value) - ) + tag: string + value: number } function toMetric(payload: DemoPlcPayload, timestamp: number): DemoPlcMetric { @@ -52,12 +39,7 @@ async function postMetric(metric: DemoPlcMetric): Promise { if (!response.ok) { const text = await response.text() - console.error('demo.plc.post_error', { - status: response.status, - statusText: response.statusText, - body: text.slice(0, 500), - }) - return + throw new Error(text) } console.log('demo.plc.posted', { tag: metric.tag }) @@ -66,20 +48,7 @@ async function postMetric(metric: DemoPlcMetric): Promise { export const handleDemoPlc: TopicHandler = async (topic, payload) => { console.log('demo.plc.received', { topic, bytes: payload.length }) - let value: unknown - - try { - value = parseJson(payload) - } catch (err) { - console.warn('demo.plc.invalid_json', { topic, err }) - return - } - - if (!isDemoPlcPayload(value)) { - console.warn('demo.plc.invalid_payload', { topic }) - return - } - + const value = parseJson(payload) const metric = toMetric(value, Date.now()) await postMetric(metric) } diff --git a/app/src/handlers/edge5-modbus-v2.ts b/app/src/handlers/edge5-modbus-v2.ts index 0897155..cd69336 100644 --- a/app/src/handlers/edge5-modbus-v2.ts +++ b/app/src/handlers/edge5-modbus-v2.ts @@ -43,12 +43,7 @@ async function postMetrics(metrics: MappedMetric[]): Promise { if (!response.ok) { const text = await response.text() - console.error('edge5.modbus.v2.post_error', { - status: response.status, - statusText: response.statusText, - body: text.slice(0, 500), - }) - return + throw new Error(text) } console.log('edge5.modbus.v2.posted', { count: metrics.length }) @@ -57,15 +52,7 @@ async function postMetrics(metrics: MappedMetric[]): Promise { export const handleEdge5ModbusV2: TopicHandler = async (topic, payload) => { console.log('edge5.modbus.v2.received', { topic, bytes: payload.length }) - let values: number[] - - try { - values = parseValues(payload) - } catch (err) { - console.warn('edge5.modbus.v2.invalid_payload', { topic, err }) - return - } - + const values = parseValues(payload) const metrics = mapper.mapValues(values, Date.now()) await postMetrics(metrics) } diff --git a/app/src/mapping.ts b/app/src/mapping.ts index 11b113d..c08300c 100644 --- a/app/src/mapping.ts +++ b/app/src/mapping.ts @@ -1,6 +1,4 @@ import { readFileSync } from 'node:fs' -import { isAbsolute, resolve } from 'node:path' -import { fileURLToPath } from 'node:url' export type MappedMetric = { edge: string @@ -23,88 +21,30 @@ export type MetricMapper = { } type MetricMapperOptions = { + // filePath is set as a URL from import.meta.url for bundled mappings, + // or as a path string resolved by Node from the process working directory. filePath: string | URL } -function resolveMappingPath(filePath: string | URL): string { - if (filePath instanceof URL) { - return fileURLToPath(filePath) - } - - return isAbsolute(filePath) ? filePath : resolve(process.cwd(), filePath) -} - function readMappingConfig(filePath: string | URL): MappingConfig { - const resolvedPath = resolveMappingPath(filePath) - let raw: unknown - - try { - raw = JSON.parse(readFileSync(resolvedPath, 'utf8')) as unknown - } catch (err) { - throw new Error(`Failed to read mapping file ${resolvedPath}: ${String(err)}`) - } - - if (!isMappingConfig(raw)) { - throw new Error(`Invalid mapping file ${resolvedPath}`) - } - - return raw -} - -function isMappingConfig(value: unknown): value is MappingConfig { - if (!value || typeof value !== 'object') { - return false - } - - const candidate = value as Partial - - return ( - typeof candidate.edge === 'string' && - candidate.edge.length > 0 && - Array.isArray(candidate.tags) && - candidate.tags.length > 0 && - candidate.tags.every(isMappingTagEntry) - ) -} - -function isMappingTagEntry(value: unknown): value is MappingTagEntry { - return ( - (typeof value === 'string' && value.length > 0) || - (Boolean(value) && - typeof value === 'object' && - ((typeof (value as { tag?: unknown }).tag === 'string' && - (value as { tag: string }).tag.length > 0) || - (typeof (value as { key?: unknown }).key === 'string' && - (value as { key: string }).key.length > 0))) - ) -} - -function getTag(entry: MappingTagEntry): string { - if (typeof entry === 'string') { - return entry - } - - return 'tag' in entry ? entry.tag : entry.key + return JSON.parse(readFileSync(filePath, 'utf8')) as MappingConfig } export function createMetricMapper(options: MetricMapperOptions): MetricMapper { const config = readMappingConfig(options.filePath) - const tags = config.tags.map(getTag) + const tags = config.tags.map((entry) => + typeof entry === 'string' ? entry : 'tag' in entry ? entry.tag : entry.key, + ) return { edge: config.edge, tagCount: tags.length, - mapValues: (values, timestamp) => { - if (values.length !== tags.length) { - throw new Error(`Expected ${tags.length} values, got ${values.length}`) - } - - return values.map((value, index) => ({ + mapValues: (values, timestamp) => + values.map((value, index) => ({ edge: config.edge, timestamp, tag: tags[index], value, - })) - }, + })), } }