Skip to content

Commit b17b544

Browse files
move sparkplug decoding to backend
1 parent 72400af commit b17b544

File tree

12 files changed

+4026
-4290
lines changed

12 files changed

+4026
-4290
lines changed

app/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
"d3-shape": "^1.3.5",
2929
"diff": "^4.0.1",
3030
"dot-prop": "^5.0.0",
31-
"file-loader": "6",
3231
"get-value": "^3.0.1",
3332
"immutable": "^4.0.0-rc.12",
3433
"in-viewport": "^3.6.0",
@@ -73,6 +72,7 @@
7372
"chai": "^4.2.0",
7473
"cross-env": "^7.0.2",
7574
"css-loader": "^3.0.0",
75+
"file-loader": "^6.2.0",
7676
"html-webpack-plugin": "^5.5.0",
7777
"lodash": "^4.17.21",
7878
"mocha": "^9.2.1",
@@ -90,4 +90,4 @@
9090
"peerDependencies": {
9191
"electron": "^17"
9292
}
93-
}
93+
}

app/src/components/Sidebar/ValueRenderer/ValueRenderer.tsx

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import * as q from '../../../../../backend/src/Model'
22
import * as React from 'react'
3-
import * as fs from 'fs'
43
import CodeDiff from '../CodeDiff'
54
import { AppState } from '../../../reducers'
65
import { Base64Message } from '../../../../../backend/src/Model/Base64Message'
7-
import { Payload } from '../../../../../backend/src/Model/sparkplugb'
6+
import { SparkplugPayload } from '../../../../../backend/src/Model/SparkplugB'
87
import { connect } from 'react-redux'
98
import { ValueRendererDisplayMode } from '../../../reducers/Settings'
109
import { Fade } from '@material-ui/core'
10+
import { Decoder } from '../../../../../backend/src/Model/Decoder'
1111

1212
interface Props {
1313
message: q.Message
@@ -49,20 +49,7 @@ class ValueRenderer extends React.Component<Props, State> {
4949
try {
5050
JSON.parse(str)
5151
} catch (error) {
52-
try {
53-
//Sparkplugb
54-
if (Payload === undefined) {
55-
throw Error('sparkplugb.Payload is not loaded yet')
56-
}
57-
let json = Payload.toObject(Payload.decode(Base64Message.toUint8Array(msg)), {
58-
longs: String,
59-
enums: String,
60-
bytes: String,
61-
})
62-
return [JSON.stringify(json, undefined, ' '), 'json']
63-
} catch (error) {
64-
return [str, undefined]
65-
}
52+
return [str, undefined]
6653
}
6754

6855
return [this.messageToPrettyJson(str), 'json']
@@ -98,7 +85,10 @@ class ValueRenderer extends React.Component<Props, State> {
9885
}
9986

10087
public render() {
101-
return <div style={{ padding: '0px 0px 8px 0px', width: '100%' }}>{this.renderValue()}</div>
88+
return <div style={{ padding: '0px 0px 8px 0px', width: '100%' }}>
89+
{this.props.message?.payload?.decoder === Decoder.SPARKPLUG && "Decoded SparkplugB"}
90+
{this.renderValue()}
91+
</div>
10292
}
10393

10494
public renderValue() {

app/src/components/TopicPlot.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import PlotHistory from './Chart/Chart'
55
import { Base64Message } from '../../../backend/src/Model/Base64Message'
66
import { toPlottableValue } from './Sidebar/CodeDiff/util'
77
import { PlotCurveTypes } from '../reducers/Charts'
8-
import { Payload } from '../../../backend/src/Model/sparkplugb'
98
const parseDuration = require('parse-duration')
109

1110
interface Props {
@@ -41,7 +40,7 @@ function nodeDotPathToHistory(startTime: number | undefined, history: q.MessageH
4140
let json: any = {}
4241
try {
4342
json = message.payload ? JSON.parse(Base64Message.toUnicodeString(message.payload)) : {}
44-
} catch (ignore) {}
43+
} catch (ignore) { }
4544

4645
const value = dotProp.get(json, dotPath)
4746

app/src/index.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,9 @@ import { connect, Provider } from 'react-redux'
1010
import { ThemeProvider } from '@material-ui/styles'
1111
import './utils/tracking'
1212
import { themes } from './theme'
13-
import { loadSparkplugBPayload } from '../../backend/src/Model/sparkplugb'
1413

1514
const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
1615
const store = createStore(reducers, composeEnhancers(applyMiddleware(reduxThunk, batchDispatchMiddleware)))
17-
loadSparkplugBPayload()
1816

1917
function ApplicationRenderer(props: { theme: 'light' | 'dark' }) {
2018
return (

app/yarn.lock

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2054,13 +2054,13 @@ faye-websocket@^0.11.3:
20542054
dependencies:
20552055
websocket-driver ">=0.5.1"
20562056

2057-
file-loader@6:
2058-
version "6.0.0"
2059-
resolved "https://registry.npmjs.org/file-loader/-/file-loader-6.0.0.tgz"
2060-
integrity sha512-/aMOAYEFXDdjG0wytpTL5YQLfZnnTmLNjn+AIrJ/6HVnTfDqLsVKUUwkDf4I4kgex36BvjuXEn/TX9B/1ESyqQ==
2057+
file-loader@^6.2.0:
2058+
version "6.2.0"
2059+
resolved "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz"
2060+
integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==
20612061
dependencies:
20622062
loader-utils "^2.0.0"
2063-
schema-utils "^2.6.5"
2063+
schema-utils "^3.0.0"
20642064

20652065
fill-range@^7.0.1:
20662066
version "7.0.1"
@@ -3766,7 +3766,7 @@ schema-utils@^2.6.5:
37663766
ajv "^6.12.0"
37673767
ajv-keywords "^3.4.1"
37683768

3769-
schema-utils@^3.1.0, schema-utils@^3.1.1:
3769+
schema-utils@^3.0.0, schema-utils@^3.1.0, schema-utils@^3.1.1:
37703770
version "3.1.1"
37713771
resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz"
37723772
integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==

backend/src/Model/Base64Message.ts

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1-
const { Base64 } = require('js-base64')
1+
2+
import { Base64 } from 'js-base64'
3+
import { Decoder } from './Decoder'
24

35
export class Base64Message {
46
private base64Message: string
57
private unicodeValue: string
6-
8+
public decoder: Decoder
79
public length: number
810

911
private constructor(base64Str: string) {
1012
this.base64Message = base64Str
1113
this.unicodeValue = Base64.decode(base64Str)
1214
this.length = base64Str.length
15+
this.decoder = Decoder.NONE
1316
}
1417

1518
public static toUnicodeString(message: Base64Message) {
@@ -27,15 +30,4 @@ export class Base64Message {
2730
public static toDataUri(message: Base64Message, mimeType: string) {
2831
return `data:${mimeType};base64,${message.base64Message}`
2932
}
30-
31-
public static toUint8Array(message: Base64Message) {
32-
const binaryString = window.atob(message.base64Message)
33-
const len = binaryString.length
34-
const bytes = new Uint8Array(len)
35-
for (const i of Array.from(Array(len).keys())) {
36-
bytes[i] = binaryString.charCodeAt(i)
37-
}
38-
39-
return bytes
40-
}
4133
}

backend/src/Model/Decoder.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export enum Decoder {
2+
NONE,
3+
SPARKPLUG
4+
}

backend/src/Model/sparkplugb.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,24 @@
1-
const protobuf = require('protobufjs')
2-
const sparkplugBProto = require('../../../res/sparkplug_b.proto')
1+
import { readFileSync } from 'fs'
2+
import * as protobuf from 'protobufjs'
3+
import { Base64Message } from './Base64Message';
4+
import { Decoder } from './Decoder';
35

4-
export let Payload = undefined
6+
const buffer = readFileSync(require.resolve('../../../../res/sparkplug_b.proto'));
7+
const root = protobuf.parse(buffer.toString()).root
8+
export let SparkplugPayload = root.lookupType('com.cirruslink.sparkplug.protobuf.Payload')
59

6-
export function loadSparkplugBPayload() {
7-
protobuf.load(sparkplugBProto).then((root: any) => {
8-
Payload = root.lookupType('com.cirruslink.sparkplug.protobuf.Payload')
9-
})
10+
export const SparkplugDecoder = {
11+
decode(input: Buffer): Base64Message | undefined {
12+
try {
13+
let message = Base64Message.fromString(
14+
JSON.stringify(
15+
SparkplugPayload.toObject(SparkplugPayload.decode(new Uint8Array(input)))
16+
)
17+
)
18+
message.decoder = Decoder.SPARKPLUG
19+
return message
20+
} catch {
21+
// ignore
22+
}
23+
}
1024
}

backend/src/Model/spec/makeTreeNode.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,42 @@ import { TreeNodeFactory } from '../'
22
import { Base64Message } from '../Base64Message'
33
import { TreeNode } from '../TreeNode'
44
import { MqttMessage } from '../../../../events'
5+
import { SparkplugPayload } from '../sparkplugb'
6+
7+
interface Decoder {
8+
decode(input: string): string | null
9+
}
10+
11+
const SparkplugDecoder = {
12+
decoderTime: 0,
13+
encoder: new TextEncoder(),
14+
decode(input: string): string | null {
15+
if (!SparkplugPayload) {
16+
return null
17+
}
18+
19+
const start = performance.now()
20+
21+
let result
22+
try {
23+
result = JSON.stringify(SparkplugPayload.toObject(SparkplugPayload.decode(this.encoder.encode(input))))
24+
} catch { }
25+
26+
this.decoderTime += performance.now() - start;
27+
return result ?? null
28+
}
29+
}
30+
31+
let i = 1
32+
setInterval(() => {
33+
console.log(`decoder time after ${i++ * 10} seconds: ${SparkplugDecoder.decoderTime}ms`)
34+
}, 10000)
535

636
export function makeTreeNode(topic: string, message?: string): TreeNode<any> {
37+
let sparkplugMessage = message && SparkplugDecoder.decode(message)
738
const mqttMessage: MqttMessage = {
839
topic,
9-
payload: message ? Base64Message.fromString(message) : null,
40+
payload: message ? Base64Message.fromString(sparkplugMessage ?? message) : null,
1041
qos: 0,
1142
retain: false,
1243
messageId: undefined,

backend/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
makePublishEvent,
1111
removeConnection,
1212
} from '../../events'
13+
import { SparkplugDecoder } from './Model/sparkplugb'
1314

1415
export class ConnectionManager {
1516
private connections: { [s: string]: DataSource<any> } = {}
@@ -48,7 +49,7 @@ export class ConnectionManager {
4849

4950
backendEvents.emit(messageEvent, {
5051
topic,
51-
payload: Base64Message.fromBuffer(buffer),
52+
payload: SparkplugDecoder.decode(buffer) ?? Base64Message.fromBuffer(buffer),
5253
qos: packet.qos,
5354
retain: packet.retain,
5455
messageId: packet.messageId,

0 commit comments

Comments
 (0)