move sparkplug decoding to backend
This commit is contained in:
@@ -28,7 +28,6 @@
|
|||||||
"d3-shape": "^1.3.5",
|
"d3-shape": "^1.3.5",
|
||||||
"diff": "^4.0.1",
|
"diff": "^4.0.1",
|
||||||
"dot-prop": "^5.0.0",
|
"dot-prop": "^5.0.0",
|
||||||
"file-loader": "6",
|
|
||||||
"get-value": "^3.0.1",
|
"get-value": "^3.0.1",
|
||||||
"immutable": "^4.0.0-rc.12",
|
"immutable": "^4.0.0-rc.12",
|
||||||
"in-viewport": "^3.6.0",
|
"in-viewport": "^3.6.0",
|
||||||
@@ -73,6 +72,7 @@
|
|||||||
"chai": "^4.2.0",
|
"chai": "^4.2.0",
|
||||||
"cross-env": "^7.0.2",
|
"cross-env": "^7.0.2",
|
||||||
"css-loader": "^3.0.0",
|
"css-loader": "^3.0.0",
|
||||||
|
"file-loader": "^6.2.0",
|
||||||
"html-webpack-plugin": "^5.5.0",
|
"html-webpack-plugin": "^5.5.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"mocha": "^9.2.1",
|
"mocha": "^9.2.1",
|
||||||
@@ -90,4 +90,4 @@
|
|||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"electron": "^17"
|
"electron": "^17"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import * as q from '../../../../../backend/src/Model'
|
import * as q from '../../../../../backend/src/Model'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import * as fs from 'fs'
|
|
||||||
import CodeDiff from '../CodeDiff'
|
import CodeDiff from '../CodeDiff'
|
||||||
import { AppState } from '../../../reducers'
|
import { AppState } from '../../../reducers'
|
||||||
import { Base64Message } from '../../../../../backend/src/Model/Base64Message'
|
import { Base64Message } from '../../../../../backend/src/Model/Base64Message'
|
||||||
import { Payload } from '../../../../../backend/src/Model/sparkplugb'
|
import { SparkplugPayload } from '../../../../../backend/src/Model/SparkplugB'
|
||||||
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'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
message: q.Message
|
message: q.Message
|
||||||
@@ -49,20 +49,7 @@ class ValueRenderer extends React.Component<Props, State> {
|
|||||||
try {
|
try {
|
||||||
JSON.parse(str)
|
JSON.parse(str)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
try {
|
return [str, undefined]
|
||||||
//Sparkplugb
|
|
||||||
if (Payload === undefined) {
|
|
||||||
throw Error('sparkplugb.Payload is not loaded yet')
|
|
||||||
}
|
|
||||||
let json = Payload.toObject(Payload.decode(Base64Message.toUint8Array(msg)), {
|
|
||||||
longs: String,
|
|
||||||
enums: String,
|
|
||||||
bytes: String,
|
|
||||||
})
|
|
||||||
return [JSON.stringify(json, undefined, ' '), 'json']
|
|
||||||
} catch (error) {
|
|
||||||
return [str, undefined]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [this.messageToPrettyJson(str), 'json']
|
return [this.messageToPrettyJson(str), 'json']
|
||||||
@@ -98,7 +85,10 @@ class ValueRenderer extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return <div style={{ padding: '0px 0px 8px 0px', width: '100%' }}>{this.renderValue()}</div>
|
return <div style={{ padding: '0px 0px 8px 0px', width: '100%' }}>
|
||||||
|
{this.props.message?.payload?.decoder === Decoder.SPARKPLUG && "Decoded SparkplugB"}
|
||||||
|
{this.renderValue()}
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
public renderValue() {
|
public renderValue() {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import PlotHistory from './Chart/Chart'
|
|||||||
import { Base64Message } from '../../../backend/src/Model/Base64Message'
|
import { Base64Message } from '../../../backend/src/Model/Base64Message'
|
||||||
import { toPlottableValue } from './Sidebar/CodeDiff/util'
|
import { toPlottableValue } from './Sidebar/CodeDiff/util'
|
||||||
import { PlotCurveTypes } from '../reducers/Charts'
|
import { PlotCurveTypes } from '../reducers/Charts'
|
||||||
import { Payload } from '../../../backend/src/Model/sparkplugb'
|
|
||||||
const parseDuration = require('parse-duration')
|
const parseDuration = require('parse-duration')
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -41,7 +40,7 @@ function nodeDotPathToHistory(startTime: number | undefined, history: q.MessageH
|
|||||||
let json: any = {}
|
let json: any = {}
|
||||||
try {
|
try {
|
||||||
json = message.payload ? JSON.parse(Base64Message.toUnicodeString(message.payload)) : {}
|
json = message.payload ? JSON.parse(Base64Message.toUnicodeString(message.payload)) : {}
|
||||||
} catch (ignore) {}
|
} catch (ignore) { }
|
||||||
|
|
||||||
const value = dotProp.get(json, dotPath)
|
const value = dotProp.get(json, dotPath)
|
||||||
|
|
||||||
|
|||||||
@@ -10,11 +10,9 @@ import { connect, Provider } from 'react-redux'
|
|||||||
import { ThemeProvider } from '@material-ui/styles'
|
import { ThemeProvider } from '@material-ui/styles'
|
||||||
import './utils/tracking'
|
import './utils/tracking'
|
||||||
import { themes } from './theme'
|
import { themes } from './theme'
|
||||||
import { loadSparkplugBPayload } from '../../backend/src/Model/sparkplugb'
|
|
||||||
|
|
||||||
const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
|
const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
|
||||||
const store = createStore(reducers, composeEnhancers(applyMiddleware(reduxThunk, batchDispatchMiddleware)))
|
const store = createStore(reducers, composeEnhancers(applyMiddleware(reduxThunk, batchDispatchMiddleware)))
|
||||||
loadSparkplugBPayload()
|
|
||||||
|
|
||||||
function ApplicationRenderer(props: { theme: 'light' | 'dark' }) {
|
function ApplicationRenderer(props: { theme: 'light' | 'dark' }) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -2054,13 +2054,13 @@ faye-websocket@^0.11.3:
|
|||||||
dependencies:
|
dependencies:
|
||||||
websocket-driver ">=0.5.1"
|
websocket-driver ">=0.5.1"
|
||||||
|
|
||||||
file-loader@6:
|
file-loader@^6.2.0:
|
||||||
version "6.0.0"
|
version "6.2.0"
|
||||||
resolved "https://registry.npmjs.org/file-loader/-/file-loader-6.0.0.tgz"
|
resolved "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz"
|
||||||
integrity sha512-/aMOAYEFXDdjG0wytpTL5YQLfZnnTmLNjn+AIrJ/6HVnTfDqLsVKUUwkDf4I4kgex36BvjuXEn/TX9B/1ESyqQ==
|
integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==
|
||||||
dependencies:
|
dependencies:
|
||||||
loader-utils "^2.0.0"
|
loader-utils "^2.0.0"
|
||||||
schema-utils "^2.6.5"
|
schema-utils "^3.0.0"
|
||||||
|
|
||||||
fill-range@^7.0.1:
|
fill-range@^7.0.1:
|
||||||
version "7.0.1"
|
version "7.0.1"
|
||||||
@@ -3766,7 +3766,7 @@ schema-utils@^2.6.5:
|
|||||||
ajv "^6.12.0"
|
ajv "^6.12.0"
|
||||||
ajv-keywords "^3.4.1"
|
ajv-keywords "^3.4.1"
|
||||||
|
|
||||||
schema-utils@^3.1.0, schema-utils@^3.1.1:
|
schema-utils@^3.0.0, schema-utils@^3.1.0, schema-utils@^3.1.1:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz"
|
resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz"
|
||||||
integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==
|
integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
const { Base64 } = require('js-base64')
|
|
||||||
|
import { Base64 } from 'js-base64'
|
||||||
|
import { Decoder } from './Decoder'
|
||||||
|
|
||||||
export class Base64Message {
|
export class Base64Message {
|
||||||
private base64Message: string
|
private base64Message: string
|
||||||
private unicodeValue: string
|
private unicodeValue: string
|
||||||
|
public decoder: Decoder
|
||||||
public length: number
|
public length: number
|
||||||
|
|
||||||
private constructor(base64Str: string) {
|
private constructor(base64Str: string) {
|
||||||
this.base64Message = base64Str
|
this.base64Message = base64Str
|
||||||
this.unicodeValue = Base64.decode(base64Str)
|
this.unicodeValue = Base64.decode(base64Str)
|
||||||
this.length = base64Str.length
|
this.length = base64Str.length
|
||||||
|
this.decoder = Decoder.NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
public static toUnicodeString(message: Base64Message) {
|
public static toUnicodeString(message: Base64Message) {
|
||||||
@@ -27,15 +30,4 @@ export class Base64Message {
|
|||||||
public static toDataUri(message: Base64Message, mimeType: string) {
|
public static toDataUri(message: Base64Message, mimeType: string) {
|
||||||
return `data:${mimeType};base64,${message.base64Message}`
|
return `data:${mimeType};base64,${message.base64Message}`
|
||||||
}
|
}
|
||||||
|
|
||||||
public static toUint8Array(message: Base64Message) {
|
|
||||||
const binaryString = window.atob(message.base64Message)
|
|
||||||
const len = binaryString.length
|
|
||||||
const bytes = new Uint8Array(len)
|
|
||||||
for (const i of Array.from(Array(len).keys())) {
|
|
||||||
bytes[i] = binaryString.charCodeAt(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytes
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
4
backend/src/Model/Decoder.ts
Normal file
4
backend/src/Model/Decoder.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export enum Decoder {
|
||||||
|
NONE,
|
||||||
|
SPARKPLUG
|
||||||
|
}
|
||||||
@@ -1,10 +1,24 @@
|
|||||||
const protobuf = require('protobufjs')
|
import { readFileSync } from 'fs'
|
||||||
const sparkplugBProto = require('../../../res/sparkplug_b.proto')
|
import * as protobuf from 'protobufjs'
|
||||||
|
import { Base64Message } from './Base64Message';
|
||||||
|
import { Decoder } from './Decoder';
|
||||||
|
|
||||||
export let Payload = undefined
|
const buffer = readFileSync(require.resolve('../../../../res/sparkplug_b.proto'));
|
||||||
|
const root = protobuf.parse(buffer.toString()).root
|
||||||
|
export let SparkplugPayload = root.lookupType('com.cirruslink.sparkplug.protobuf.Payload')
|
||||||
|
|
||||||
export function loadSparkplugBPayload() {
|
export const SparkplugDecoder = {
|
||||||
protobuf.load(sparkplugBProto).then((root: any) => {
|
decode(input: Buffer): Base64Message | undefined {
|
||||||
Payload = root.lookupType('com.cirruslink.sparkplug.protobuf.Payload')
|
try {
|
||||||
})
|
let message = Base64Message.fromString(
|
||||||
|
JSON.stringify(
|
||||||
|
SparkplugPayload.toObject(SparkplugPayload.decode(new Uint8Array(input)))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
message.decoder = Decoder.SPARKPLUG
|
||||||
|
return message
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,42 @@ import { TreeNodeFactory } from '../'
|
|||||||
import { Base64Message } from '../Base64Message'
|
import { Base64Message } from '../Base64Message'
|
||||||
import { TreeNode } from '../TreeNode'
|
import { TreeNode } from '../TreeNode'
|
||||||
import { MqttMessage } from '../../../../events'
|
import { MqttMessage } from '../../../../events'
|
||||||
|
import { SparkplugPayload } from '../sparkplugb'
|
||||||
|
|
||||||
|
interface Decoder {
|
||||||
|
decode(input: string): string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
const SparkplugDecoder = {
|
||||||
|
decoderTime: 0,
|
||||||
|
encoder: new TextEncoder(),
|
||||||
|
decode(input: string): string | null {
|
||||||
|
if (!SparkplugPayload) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const start = performance.now()
|
||||||
|
|
||||||
|
let result
|
||||||
|
try {
|
||||||
|
result = JSON.stringify(SparkplugPayload.toObject(SparkplugPayload.decode(this.encoder.encode(input))))
|
||||||
|
} catch { }
|
||||||
|
|
||||||
|
this.decoderTime += performance.now() - start;
|
||||||
|
return result ?? null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let i = 1
|
||||||
|
setInterval(() => {
|
||||||
|
console.log(`decoder time after ${i++ * 10} seconds: ${SparkplugDecoder.decoderTime}ms`)
|
||||||
|
}, 10000)
|
||||||
|
|
||||||
export function makeTreeNode(topic: string, message?: string): TreeNode<any> {
|
export function makeTreeNode(topic: string, message?: string): TreeNode<any> {
|
||||||
|
let sparkplugMessage = message && SparkplugDecoder.decode(message)
|
||||||
const mqttMessage: MqttMessage = {
|
const mqttMessage: MqttMessage = {
|
||||||
topic,
|
topic,
|
||||||
payload: message ? Base64Message.fromString(message) : null,
|
payload: message ? Base64Message.fromString(sparkplugMessage ?? message) : null,
|
||||||
qos: 0,
|
qos: 0,
|
||||||
retain: false,
|
retain: false,
|
||||||
messageId: undefined,
|
messageId: undefined,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
makePublishEvent,
|
makePublishEvent,
|
||||||
removeConnection,
|
removeConnection,
|
||||||
} from '../../events'
|
} from '../../events'
|
||||||
|
import { SparkplugDecoder } from './Model/sparkplugb'
|
||||||
|
|
||||||
export class ConnectionManager {
|
export class ConnectionManager {
|
||||||
private connections: { [s: string]: DataSource<any> } = {}
|
private connections: { [s: string]: DataSource<any> } = {}
|
||||||
@@ -48,7 +49,7 @@ export class ConnectionManager {
|
|||||||
|
|
||||||
backendEvents.emit(messageEvent, {
|
backendEvents.emit(messageEvent, {
|
||||||
topic,
|
topic,
|
||||||
payload: Base64Message.fromBuffer(buffer),
|
payload: SparkplugDecoder.decode(buffer) ?? Base64Message.fromBuffer(buffer),
|
||||||
qos: packet.qos,
|
qos: packet.qos,
|
||||||
retain: packet.retain,
|
retain: packet.retain,
|
||||||
messageId: packet.messageId,
|
messageId: packet.messageId,
|
||||||
|
|||||||
@@ -108,7 +108,7 @@
|
|||||||
"electron-log": "4.4.6",
|
"electron-log": "4.4.6",
|
||||||
"electron-updater": "^4.6",
|
"electron-updater": "^4.6",
|
||||||
"fs-extra": "9",
|
"fs-extra": "9",
|
||||||
"js-base64": "^2.5.1",
|
"js-base64": "^3.7.2",
|
||||||
"json-to-ast": "^2.1.0",
|
"json-to-ast": "^2.1.0",
|
||||||
"lowdb": "^1.0.0",
|
"lowdb": "^1.0.0",
|
||||||
"mime": "^2.4.4",
|
"mime": "^2.4.4",
|
||||||
@@ -118,4 +118,4 @@
|
|||||||
"uuid": "^8.3.2",
|
"uuid": "^8.3.2",
|
||||||
"yarn-run-all": "^3.1.1"
|
"yarn-run-all": "^3.1.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user