fix: repair types
This commit is contained in:
@@ -2,7 +2,7 @@ import { Action, ActionTypes } from '../reducers/Publish'
|
|||||||
import { AppState } from '../reducers'
|
import { AppState } from '../reducers'
|
||||||
import { Base64Message } from '../../../backend/src/Model/Base64Message'
|
import { Base64Message } from '../../../backend/src/Model/Base64Message'
|
||||||
import { Dispatch } from 'redux'
|
import { Dispatch } from 'redux'
|
||||||
import { makePublishEvent, rendererEvents } from '../../../events'
|
import { MqttMessage, makePublishEvent, rendererEvents } from '../../../events'
|
||||||
|
|
||||||
export const setTopic = (topic?: string): Action => {
|
export const setTopic = (topic?: string): Action => {
|
||||||
return {
|
return {
|
||||||
@@ -41,7 +41,7 @@ export const publish = (connectionId: string) => (dispatch: Dispatch<Action>, ge
|
|||||||
}
|
}
|
||||||
|
|
||||||
const publishEvent = makePublishEvent(connectionId)
|
const publishEvent = makePublishEvent(connectionId)
|
||||||
const mqttMessage = {
|
const mqttMessage: Partial<MqttMessage> = {
|
||||||
topic,
|
topic,
|
||||||
payload: state.publish.payload ? Base64Message.fromString(state.publish.payload) : null,
|
payload: state.publish.payload ? Base64Message.fromString(state.publish.payload) : null,
|
||||||
retain: state.publish.retain,
|
retain: state.publish.retain,
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import * as q from '../../../../backend/src/Model'
|
import * as q from '../../../../backend/src/Model'
|
||||||
import React, { useState, useEffect, useCallback } from 'react'
|
import React, { useState, useEffect, useCallback } from 'react'
|
||||||
import ExpandMore from '@material-ui/icons/ExpandMore'
|
|
||||||
import NodeStats from './NodeStats'
|
import NodeStats from './NodeStats'
|
||||||
import ValuePanel from './ValueRenderer/ValuePanel'
|
import ValuePanel from './ValueRenderer/ValuePanel'
|
||||||
import { AppState } from '../../reducers'
|
import { AppState } from '../../reducers'
|
||||||
import { Badge, ExpansionPanel, ExpansionPanelDetails, ExpansionPanelSummary, Typography } from '@material-ui/core'
|
import { ExpansionPanelDetails } from '@material-ui/core'
|
||||||
import { bindActionCreators } from 'redux'
|
import { bindActionCreators } from 'redux'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { settingsActions, sidebarActions } from '../../actions'
|
import { settingsActions, sidebarActions } from '../../actions'
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ export const MessageHistory: React.FC<Props> = props => {
|
|||||||
const history = node.messageHistory.toArray()
|
const history = node.messageHistory.toArray()
|
||||||
let previousMessage: q.Message | undefined = node.message
|
let previousMessage: q.Message | undefined = node.message
|
||||||
const historyElements = [...history].reverse().map((message, idx) => {
|
const historyElements = [...history].reverse().map((message, idx) => {
|
||||||
const value = node.message ? decodeMessage(node.message)?.format()[0] ?? null : null
|
const value = node.message ? decodeMessage(message)?.message?.format()[0] ?? null : null
|
||||||
|
|
||||||
const element = {
|
const element = {
|
||||||
value: value ?? '',
|
value: value ?? '',
|
||||||
@@ -96,7 +96,7 @@ export const MessageHistory: React.FC<Props> = props => {
|
|||||||
return element
|
return element
|
||||||
})
|
})
|
||||||
|
|
||||||
const value = node.message ? decodeMessage(node.message)?.format()[0] ?? null : null
|
const value = node.message ? decodeMessage(node.message)?.message?.format()[0] ?? null : null
|
||||||
|
|
||||||
const isMessagePlottable = isPlottable(value)
|
const isMessagePlottable = isPlottable(value)
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ function ValuePanel(props: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getDecodedValue = useCallback(() => {
|
const getDecodedValue = useCallback(() => {
|
||||||
return node?.message && decodeMessage(node.message)?.toUnicodeString()
|
return node?.message && decodeMessage(node.message)?.message?.toUnicodeString()
|
||||||
}, [node, decodeMessage])
|
}, [node, decodeMessage])
|
||||||
|
|
||||||
function messageMetaInfo() {
|
function messageMetaInfo() {
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import * as q from '../../../../../backend/src/Model'
|
import * as q from '../../../../../backend/src/Model'
|
||||||
import * as React from 'react'
|
import React, { useMemo } from 'react'
|
||||||
import CodeDiff from '../CodeDiff'
|
import CodeDiff from '../CodeDiff'
|
||||||
import { AppState } from '../../../reducers'
|
import { AppState } from '../../../reducers'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { ValueRendererDisplayMode } from '../../../reducers/Settings'
|
import { ValueRendererDisplayMode } from '../../../reducers/Settings'
|
||||||
import { Fade } from '@material-ui/core'
|
import { Fade } from '@material-ui/core'
|
||||||
import { Decoder } from '../../../../../backend/src/Model/Decoder'
|
import { Decoder } from '../../../../../backend/src/Model/Decoder'
|
||||||
import { DecoderFunction, useDecoder } from '../../hooks/useDecoder'
|
import { useDecoder } from '../../hooks/useDecoder'
|
||||||
|
import { TopicViewModel } from '../../../model/TopicViewModel'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
message: q.Message
|
message: q.Message
|
||||||
@@ -15,86 +16,112 @@ interface Props {
|
|||||||
renderMode: ValueRendererDisplayMode
|
renderMode: ValueRendererDisplayMode
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ValueRenderer: React.FC<Props> = props => {
|
type Language = 'json'
|
||||||
const decodeMessage = useDecoder(props.treeNode)
|
|
||||||
|
|
||||||
function renderDiff(current: string = '', previous: string = '', title?: string, language?: 'json') {
|
function renderDiff(
|
||||||
return (
|
treeNode: q.TreeNode<TopicViewModel>,
|
||||||
<CodeDiff
|
compareWithPreviousMessage: boolean,
|
||||||
treeNode={props.treeNode}
|
current: string = '',
|
||||||
previous={previous}
|
previous: string = '',
|
||||||
current={current}
|
title?: string,
|
||||||
title={title}
|
language?: Language
|
||||||
language={language}
|
) {
|
||||||
nameOfCompareMessage={props.compareWith ? 'selected' : 'previous'}
|
return (
|
||||||
/>
|
<CodeDiff
|
||||||
)
|
treeNode={treeNode}
|
||||||
}
|
previous={previous}
|
||||||
|
current={current}
|
||||||
|
title={title}
|
||||||
|
language={language}
|
||||||
|
nameOfCompareMessage={compareWithPreviousMessage ? 'selected' : 'previous'}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function renderDiffMode(
|
function renderDiffMode(
|
||||||
decodeMessage: DecoderFunction,
|
treeNode: q.TreeNode<TopicViewModel>,
|
||||||
message: q.Message,
|
currentStr: string | undefined,
|
||||||
treeNode: q.TreeNode<any>,
|
compareStr: string | undefined,
|
||||||
compare?: q.Message
|
currentType: Language | undefined,
|
||||||
|
compareType: Language | undefined,
|
||||||
|
compareWithPreviousMessage: boolean
|
||||||
|
) {
|
||||||
|
const language = currentType === compareType && compareType === 'json' ? 'json' : undefined
|
||||||
|
|
||||||
|
return <div>{renderDiff(treeNode, compareWithPreviousMessage, currentStr, compareStr, undefined, language)}</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderRawMode(
|
||||||
|
treeNode: q.TreeNode<TopicViewModel>,
|
||||||
|
currentStr: string | undefined,
|
||||||
|
compareStr: string | undefined,
|
||||||
|
currentType: Language | undefined,
|
||||||
|
compareType: Language | undefined,
|
||||||
|
compareWithPreviousMessage: boolean
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{renderDiff(treeNode, compareWithPreviousMessage, currentStr, currentStr, undefined, currentType)}
|
||||||
|
<Fade in={Boolean(compareStr)} timeout={400}>
|
||||||
|
<div>
|
||||||
|
{Boolean(compareStr)
|
||||||
|
? renderDiff(treeNode, compareWithPreviousMessage, compareStr, compareStr, 'selected', compareType)
|
||||||
|
: null}
|
||||||
|
</div>
|
||||||
|
</Fade>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ValueRenderer: React.FC<Props> = ({ treeNode, compareWith: compare, message, renderMode }) => {
|
||||||
|
const decodeMessage = useDecoder(treeNode)
|
||||||
|
const decodedMessage = useMemo(() => decodeMessage(message), [decodeMessage, message])
|
||||||
|
|
||||||
|
const previousMessages = treeNode.messageHistory.toArray()
|
||||||
|
const previousMessage = previousMessages[previousMessages.length - 2]
|
||||||
|
const compareMessage = compare || previousMessage || message
|
||||||
|
const compareWithPreviousMessage = !!compare
|
||||||
|
|
||||||
|
const [currentStr, currentType] = useMemo(
|
||||||
|
() => decodedMessage?.message?.format(treeNode.type) ?? [],
|
||||||
|
[decodedMessage, treeNode.type]
|
||||||
|
)
|
||||||
|
const [compareStr, compareType] = useMemo(
|
||||||
|
() => decodeMessage(compareMessage)?.message?.format(treeNode.type) ?? [],
|
||||||
|
[compareMessage, decodeMessage, treeNode.type]
|
||||||
|
)
|
||||||
|
|
||||||
|
function renderValue(
|
||||||
|
treeNode: q.TreeNode<TopicViewModel>,
|
||||||
|
currentStr: string | undefined,
|
||||||
|
compareStr: string | undefined,
|
||||||
|
currentType: Language | undefined,
|
||||||
|
compareType: Language | undefined,
|
||||||
|
renderMode: string,
|
||||||
|
compareWithPreviousMessage: boolean
|
||||||
) {
|
) {
|
||||||
if (!message.payload) {
|
if (!decodedMessage) {
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const previousMessages = treeNode.messageHistory.toArray()
|
|
||||||
const previousMessage = previousMessages[previousMessages.length - 2]
|
|
||||||
const compareMessage = compare || previousMessage || message
|
|
||||||
|
|
||||||
const [currentStr, currentType] = decodeMessage(message)?.format(treeNode.type) ?? []
|
|
||||||
const [compareStr, compareType] = decodeMessage(compareMessage)?.format(treeNode.type) ?? []
|
|
||||||
|
|
||||||
const language = currentType === compareType && compareType === 'json' ? 'json' : undefined
|
|
||||||
|
|
||||||
return <div>{renderDiff(currentStr, compareStr, undefined, language)}</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderRawMode(
|
|
||||||
decodeMessage: DecoderFunction,
|
|
||||||
message: q.Message,
|
|
||||||
treeNode: q.TreeNode<any>,
|
|
||||||
compare?: q.Message
|
|
||||||
) {
|
|
||||||
if (!message.payload) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const [currentStr, currentType] = decodeMessage(message)?.format(treeNode.type) ?? []
|
|
||||||
const [compareStr, compareType] =
|
|
||||||
compare && compare.payload ? decodeMessage(compare)?.format(treeNode.type) ?? [] : []
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{renderDiff(currentStr, currentStr, undefined, currentType)}
|
|
||||||
<Fade in={Boolean(compareStr)} timeout={400}>
|
|
||||||
<div>{Boolean(compareStr) ? renderDiff(compareStr, compareStr, 'selected', compareType) : null}</div>
|
|
||||||
</Fade>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderValue(decodeMessage: DecoderFunction) {
|
|
||||||
const { message, treeNode, compareWith, renderMode } = props
|
|
||||||
if (!message.payload) {
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (renderMode) {
|
switch (renderMode) {
|
||||||
case 'diff':
|
case 'diff':
|
||||||
return renderDiffMode(decodeMessage, message, treeNode, compareWith)
|
return renderDiffMode(treeNode, currentStr, compareStr, currentType, compareType, compareWithPreviousMessage)
|
||||||
default:
|
default:
|
||||||
return renderRawMode(decodeMessage, message, treeNode, compareWith)
|
return renderRawMode(treeNode, currentStr, compareStr, currentType, compareType, compareWithPreviousMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const renderedValue = useMemo(
|
||||||
|
() =>
|
||||||
|
renderValue(treeNode, currentStr, compareStr, currentType, compareType, renderMode, compareWithPreviousMessage),
|
||||||
|
[treeNode, currentStr, compareStr, currentType, compareType, renderMode, compareWithPreviousMessage]
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ padding: '0px 0px 8px 0px', width: '100%' }}>
|
<div style={{ padding: '0px 0px 8px 0px', width: '100%' }}>
|
||||||
{props.message?.payload?.decoder === Decoder.SPARKPLUG && 'Decoded SparkplugB'}
|
{decodedMessage?.decoder === Decoder.SPARKPLUG && 'Decoded SparkplugB'}
|
||||||
{renderValue(decodeMessage)}
|
{renderedValue}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ function filterUsingTimeRange(startTime: number | undefined, data: Array<q.Messa
|
|||||||
function nodeToHistory(decodeMessage: DecoderFunction, startTime: number | undefined, history: q.MessageHistory) {
|
function nodeToHistory(decodeMessage: DecoderFunction, startTime: number | undefined, history: q.MessageHistory) {
|
||||||
return filterUsingTimeRange(startTime, history.toArray())
|
return filterUsingTimeRange(startTime, history.toArray())
|
||||||
.map((message: q.Message) => {
|
.map((message: q.Message) => {
|
||||||
const decoded = decodeMessage(message)?.toUnicodeString()
|
const decoded = decodeMessage(message)?.message?.toUnicodeString()
|
||||||
return { x: message.received.getTime(), y: toPlottableValue(decoded) }
|
return { x: message.received.getTime(), y: toPlottableValue(decoded) }
|
||||||
})
|
})
|
||||||
.filter(data => !isNaN(data.y as any)) as any
|
.filter(data => !isNaN(data.y as any)) as any
|
||||||
@@ -46,7 +46,7 @@ function nodeDotPathToHistory(
|
|||||||
.map((message: q.Message) => {
|
.map((message: q.Message) => {
|
||||||
let json: any = {}
|
let json: any = {}
|
||||||
try {
|
try {
|
||||||
const decoded = decodeMessage(message)
|
const decoded = decodeMessage(message)?.message
|
||||||
json = decoded ? JSON.parse(decoded.toUnicodeString()) : {}
|
json = decoded ? JSON.parse(decoded.toUnicodeString()) : {}
|
||||||
} catch (ignore) {}
|
} catch (ignore) {}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export const TreeNodeTitle = (props: TreeNodeProps) => {
|
|||||||
if (!props.treeNode.message || !props.treeNode.message.payload) {
|
if (!props.treeNode.message || !props.treeNode.message.payload) {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
const [value = ''] = decodeMessage(props.treeNode.message)?.format(props.treeNode.type) ?? []
|
const [value = ''] = decodeMessage(props.treeNode.message)?.message?.format(props.treeNode.type) ?? []
|
||||||
|
|
||||||
return value.length > limit ? `${value.slice(0, limit)}…` : value
|
return value.length > limit ? `${value.slice(0, limit)}…` : value
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import * as q from '../../../../backend/src/Model'
|
import * as q from '../../../../backend/src/Model'
|
||||||
import { useCallback, useState } from 'react'
|
import { useCallback, useState } from 'react'
|
||||||
import { TopicViewModel } from '../../model/TopicViewModel'
|
import { TopicViewModel } from '../../model/TopicViewModel'
|
||||||
import { Base64Message } from '../../../../backend/src/Model/Base64Message'
|
|
||||||
import { useSubscription } from './useSubscription'
|
import { useSubscription } from './useSubscription'
|
||||||
import { useViewModel } from '../Tree/TreeNode/effects/useViewModel'
|
import { useViewModel } from '../Tree/TreeNode/effects/useViewModel'
|
||||||
|
import { DecoderEnvelope } from '../../decoders/DecoderEnvelope'
|
||||||
|
import { Decoder } from '../../../../backend/src/Model/Decoder'
|
||||||
|
|
||||||
export type DecoderFunction = (message: q.Message) => Base64Message | null
|
export type DecoderFunction = (message: q.Message) => DecoderEnvelope | undefined
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the latest decoder for a topic
|
* Provides the latest decoder for a topic
|
||||||
@@ -21,7 +22,9 @@ export function useDecoder(treeNode: q.TreeNode<TopicViewModel> | undefined): De
|
|||||||
|
|
||||||
return useCallback(
|
return useCallback(
|
||||||
message => {
|
message => {
|
||||||
return decoder && message.payload ? decoder.decoder.decode(message.payload, decoder.format) : message.payload
|
return decoder && message.payload
|
||||||
|
? decoder.decoder.decode(message.payload, decoder.format)
|
||||||
|
: { message: message.payload ?? undefined, decoder: Decoder.NONE }
|
||||||
},
|
},
|
||||||
[decoder]
|
[decoder]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { Base64Message } from '../../../backend/src/Model/Base64Message'
|
import { Base64Message } from '../../../backend/src/Model/Base64Message'
|
||||||
|
import { Decoder } from '../../../backend/src/Model/Decoder'
|
||||||
|
import { DecoderEnvelope } from './DecoderEnvelope'
|
||||||
import { MessageDecoder } from './MessageDecoder'
|
import { MessageDecoder } from './MessageDecoder'
|
||||||
|
|
||||||
type BinaryFormats =
|
type BinaryFormats =
|
||||||
@@ -18,7 +20,7 @@ type BinaryFormats =
|
|||||||
*/
|
*/
|
||||||
export const BinaryDecoder: MessageDecoder<BinaryFormats> = {
|
export const BinaryDecoder: MessageDecoder<BinaryFormats> = {
|
||||||
formats: ['int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', 'uint32', 'uint64', 'float', 'double'],
|
formats: ['int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', 'uint32', 'uint64', 'float', 'double'],
|
||||||
decode(input: Base64Message, format: BinaryFormats): Base64Message {
|
decode(input: Base64Message, format: BinaryFormats): DecoderEnvelope {
|
||||||
const decodingOption = {
|
const decodingOption = {
|
||||||
int8: [Buffer.prototype.readInt8, 1],
|
int8: [Buffer.prototype.readInt8, 1],
|
||||||
int16: [Buffer.prototype.readInt16LE, 2],
|
int16: [Buffer.prototype.readInt16LE, 2],
|
||||||
@@ -37,12 +39,18 @@ export const BinaryDecoder: MessageDecoder<BinaryFormats> = {
|
|||||||
const buf = input.toBuffer()
|
const buf = input.toBuffer()
|
||||||
let str: String[] = []
|
let str: String[] = []
|
||||||
if (buf.length % bytesToRead !== 0) {
|
if (buf.length % bytesToRead !== 0) {
|
||||||
return new Base64Message(undefined, 'Data type does not align with message')
|
return {
|
||||||
|
error: 'Data type does not align with message',
|
||||||
|
decoder: Decoder.NONE,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (let index = 0; index < buf.length; index += bytesToRead) {
|
for (let index = 0; index < buf.length; index += bytesToRead) {
|
||||||
str.push((readNumber as any).apply(buf, [index]).toString())
|
str.push((readNumber as any).apply(buf, [index]).toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
return Base64Message.fromString(JSON.stringify(str.length === 1 ? str[0] : str))
|
return {
|
||||||
|
message: Base64Message.fromString(JSON.stringify(str.length === 1 ? str[0] : str)),
|
||||||
|
decoder: Decoder.NONE,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
8
app/src/decoders/DecoderEnvelope.ts
Normal file
8
app/src/decoders/DecoderEnvelope.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { Base64Message } from '../../../backend/src/Model/Base64Message'
|
||||||
|
import { Decoder } from '../../../backend/src/Model/Decoder'
|
||||||
|
|
||||||
|
export interface DecoderEnvelope {
|
||||||
|
message?: Base64Message
|
||||||
|
error?: string
|
||||||
|
decoder: Decoder
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Base64Message } from '../../../backend/src/Model/Base64Message'
|
import { Base64Message } from '../../../backend/src/Model/Base64Message'
|
||||||
|
import { DecoderEnvelope } from './DecoderEnvelope'
|
||||||
|
|
||||||
export interface MessageDecoder<T = string> {
|
export interface MessageDecoder<T = string> {
|
||||||
/**
|
/**
|
||||||
@@ -8,5 +9,5 @@ export interface MessageDecoder<T = string> {
|
|||||||
formats: T[]
|
formats: T[]
|
||||||
canDecodeTopic?(topic: string): boolean
|
canDecodeTopic?(topic: string): boolean
|
||||||
canDecodeData?(data: Base64Message): boolean
|
canDecodeData?(data: Base64Message): boolean
|
||||||
decode(input: Base64Message, format: T | string | undefined): Base64Message
|
decode(input: Base64Message, format: T | string | undefined): DecoderEnvelope
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export const SparkplugDecoder: MessageDecoder = {
|
|||||||
canDecodeTopic(topic: string) {
|
canDecodeTopic(topic: string) {
|
||||||
return !!topic.match(/^spBv1\.0\/[^/]+\/[ND](DATA|CMD|DEATH|BIRTH)\/[^/]+(\/[^/]+)?$/u)
|
return !!topic.match(/^spBv1\.0\/[^/]+\/[ND](DATA|CMD|DEATH|BIRTH)\/[^/]+(\/[^/]+)?$/u)
|
||||||
},
|
},
|
||||||
decode(input: Base64Message): Base64Message {
|
decode(input) {
|
||||||
try {
|
try {
|
||||||
const message = Base64Message.fromString(
|
const message = Base64Message.fromString(
|
||||||
JSON.stringify(
|
JSON.stringify(
|
||||||
@@ -17,12 +17,12 @@ export const SparkplugDecoder: MessageDecoder = {
|
|||||||
sparkplug.decodePayload(new Uint8Array(input.toBuffer()))
|
sparkplug.decodePayload(new Uint8Array(input.toBuffer()))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
message.decoder = Decoder.SPARKPLUG
|
return { message, decoder: Decoder.SPARKPLUG }
|
||||||
return message
|
|
||||||
} catch {
|
} catch {
|
||||||
const message = new Base64Message(undefined, 'Failed to decode sparkplugb payload')
|
return {
|
||||||
message.decoder = Decoder.NONE
|
error: 'Failed to decode sparkplugb payload',
|
||||||
return message
|
decoder: Decoder.NONE,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { Base64Message } from '../../../backend/src/Model/Base64Message'
|
import { Base64Message } from '../../../backend/src/Model/Base64Message'
|
||||||
|
import { Decoder } from '../../../backend/src/Model/Decoder'
|
||||||
import { MessageDecoder } from './MessageDecoder'
|
import { MessageDecoder } from './MessageDecoder'
|
||||||
|
|
||||||
export const StringDecoder: MessageDecoder = {
|
export const StringDecoder: MessageDecoder = {
|
||||||
formats: ['string'],
|
formats: ['string'],
|
||||||
decode(input: Base64Message): Base64Message {
|
decode(input: Base64Message) {
|
||||||
return input
|
return { message: input, decoder: Decoder.NONE }
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ export class MqttSource implements DataSource<MqttOptions> {
|
|||||||
|
|
||||||
public publish(msg: MqttMessage) {
|
public publish(msg: MqttMessage) {
|
||||||
if (this.client) {
|
if (this.client) {
|
||||||
this.client.publish(msg.topic, msg.payload?.toBuffer() ?? '', {
|
this.client.publish(msg.topic, (msg.payload && new Base64Message(msg.payload))?.toBuffer() ?? '', {
|
||||||
qos: msg.qos,
|
qos: msg.qos,
|
||||||
retain: msg.retain,
|
retain: msg.retain,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,20 +1,42 @@
|
|||||||
import { Base64 } from 'js-base64'
|
import { Base64 } from 'js-base64'
|
||||||
import { Decoder } from './Decoder'
|
|
||||||
import { TopicDataType } from './TreeNode'
|
import { TopicDataType } from './TreeNode'
|
||||||
|
|
||||||
|
export type Base64MessageDTO = Pick<Base64Message, 'base64Message'>
|
||||||
|
|
||||||
export class Base64Message {
|
export class Base64Message {
|
||||||
public base64Message: string
|
public base64Message: string
|
||||||
private unicodeValue: string
|
private _unicodeValue: string | undefined
|
||||||
public error?: string
|
|
||||||
public decoder: Decoder
|
|
||||||
public length: number
|
|
||||||
|
|
||||||
constructor(base64Str?: string, error?: string) {
|
// Todo: Rename to `encodedLength`
|
||||||
this.base64Message = base64Str ?? ''
|
public get length(): number {
|
||||||
this.error = error
|
return this.base64Message.length
|
||||||
this.unicodeValue = Base64.decode(base64Str ?? '')
|
}
|
||||||
this.length = base64Str?.length ?? 0
|
|
||||||
this.decoder = Decoder.NONE
|
private get unicodeValue(): string {
|
||||||
|
if (!this._unicodeValue) {
|
||||||
|
this._unicodeValue = Base64.decode(this.base64Message ?? '')
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._unicodeValue
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(base64Str?: string | Base64MessageDTO, error?: string) {
|
||||||
|
if (typeof base64Str === 'string' || typeof base64Str === 'undefined') {
|
||||||
|
this.base64Message = base64Str ?? ''
|
||||||
|
} else {
|
||||||
|
if (typeof base64Str.base64Message !== 'string') {
|
||||||
|
throw new Error('Received unexpected type in copy constructor')
|
||||||
|
}
|
||||||
|
this.base64Message = base64Str.base64Message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override default JSON serialization behavior to only return the DTO
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
public toJSON(): Base64MessageDTO {
|
||||||
|
return { base64Message: this.base64Message }
|
||||||
}
|
}
|
||||||
|
|
||||||
public toUnicodeString() {
|
public toUnicodeString() {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export class ChangeBuffer {
|
|||||||
public push(val: MqttMessage) {
|
public push(val: MqttMessage) {
|
||||||
if (!this.isFull()) {
|
if (!this.isFull()) {
|
||||||
this.buffer.push({ message: val, received: new Date() })
|
this.buffer.push({ message: val, received: new Date() })
|
||||||
this.size += this.estimatedMessageOverhead + (val.payload ? val.payload.length : 0)
|
this.size += this.estimatedMessageOverhead + (val.payload?.base64Message.length ?? 0)
|
||||||
this.length += 1
|
this.length += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { Base64Message } from './Base64Message'
|
import { Base64Message } from './Base64Message'
|
||||||
import { QoS } from '../DataSource/MqttSource'
|
import { QoS } from '../DataSource/MqttSource'
|
||||||
|
import { MemoryConsumptionExpressedByLength } from './RingBuffer'
|
||||||
|
|
||||||
export interface Message {
|
export interface Message extends MemoryConsumptionExpressedByLength {
|
||||||
// mqtt based info
|
// mqtt based info
|
||||||
payload: Base64Message | null
|
payload: Base64Message | null
|
||||||
messageId?: number
|
messageId?: number
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export abstract class TreeNodeFactory {
|
|||||||
node.setMessage({
|
node.setMessage({
|
||||||
...mqttMessage,
|
...mqttMessage,
|
||||||
payload: mqttMessage.payload && new Base64Message(mqttMessage.payload?.base64Message),
|
payload: mqttMessage.payload && new Base64Message(mqttMessage.payload?.base64Message),
|
||||||
length: mqttMessage.payload?.length ?? 0,
|
length: mqttMessage.payload?.base64Message.length ?? 0,
|
||||||
received: receiveDate,
|
received: receiveDate,
|
||||||
messageNumber: this.messageCounter,
|
messageNumber: this.messageCounter,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Base64Message } from '../backend/src/Model/Base64Message'
|
import { Base64MessageDTO } from '../backend/src/Model/Base64Message'
|
||||||
import { DataSourceState, MqttOptions } from '../backend/src/DataSource'
|
import { DataSourceState, MqttOptions } from '../backend/src/DataSource'
|
||||||
import { UpdateInfo } from 'builder-util-runtime'
|
import { UpdateInfo } from 'builder-util-runtime'
|
||||||
import { RpcEvent } from './EventSystem/Rpc'
|
import { RpcEvent } from './EventSystem/Rpc'
|
||||||
@@ -32,7 +32,7 @@ export const updateAvailable: Event<UpdateInfo> = {
|
|||||||
|
|
||||||
export interface MqttMessage {
|
export interface MqttMessage {
|
||||||
topic: string
|
topic: string
|
||||||
payload: Base64Message | null
|
payload: Base64MessageDTO | null
|
||||||
qos: 0 | 1 | 2
|
qos: 0 | 1 | 2
|
||||||
retain: boolean
|
retain: boolean
|
||||||
// Set if QoS is > 0 on received messages
|
// Set if QoS is > 0 on received messages
|
||||||
|
|||||||
Reference in New Issue
Block a user