From 07458cd712a8715e375b77edd534e194021f29f3 Mon Sep 17 00:00:00 2001 From: Thomas Nordquist Date: Mon, 20 Apr 2020 18:23:15 +0200 Subject: [PATCH] Expose message Ids to the user --- app/index.html | 7 ++-- app/src/actions/Settings.ts | 4 +-- app/src/actions/clearTopic.ts | 1 + .../SettingsDrawer/BrokerStatistics.tsx | 4 +-- app/src/components/Sidebar/MessageId.tsx | 20 +++++++++++ .../Sidebar/TopicPanel/TopicDeleteButton.tsx | 2 +- .../Sidebar/ValueRenderer/MessageHistory.tsx | 25 +++++++++----- .../Sidebar/ValueRenderer/ValuePanel.tsx | 16 +++++---- .../Sidebar/ValueRenderer/ValueRenderer.tsx | 12 +++---- app/src/components/TopicPlot.tsx | 4 +-- .../Tree/TreeNode/TreeNodeTitle.tsx | 6 ++-- app/src/components/Tree/TreeNode/index.tsx | 2 +- backend/src/DataSource/DataSource.ts | 2 +- backend/src/Model/Message.ts | 11 +++++- backend/src/Model/Tree.ts | 8 +---- backend/src/Model/TreeNode.ts | 9 ++--- backend/src/Model/TreeNodeFactory.ts | 16 +++++---- backend/src/Model/spec/Edge.spec.ts | 15 ++++---- backend/src/Model/spec/Tree.spec.ts | 10 +++--- .../src/Model/spec/TreeNode.findNode.spec.ts | 4 +-- backend/src/Model/spec/TreeNode.spec.ts | 34 ++++++++----------- .../src/Model/spec/TreeNodeFactory.spec.ts | 19 ++++------- backend/src/Model/spec/makeTreeNode.ts | 16 +++++++++ backend/src/index.ts | 2 ++ events/Events.ts | 2 ++ 25 files changed, 145 insertions(+), 106 deletions(-) create mode 100644 app/src/components/Sidebar/MessageId.tsx create mode 100644 backend/src/Model/spec/makeTreeNode.ts diff --git a/app/index.html b/app/index.html index 64e94ff..54d3982 100644 --- a/app/index.html +++ b/app/index.html @@ -160,7 +160,7 @@ -
+
- <% _.forEach(htmlWebpackPlugin.files.js, function(file) { %><% }); %> + <% _.forEach(htmlWebpackPlugin.files.js, function(file) { %> + + <% }); %> diff --git a/app/src/actions/Settings.ts b/app/src/actions/Settings.ts index 6fa3994..0202aff 100644 --- a/app/src/actions/Settings.ts +++ b/app/src/actions/Settings.ts @@ -112,8 +112,8 @@ export const filterTopics = (filterStr: string) => (dispatch: Dispatch, get const messageMatches = node.message && - node.message.value && - Base64Message.toUnicodeString(node.message.value).toLowerCase().indexOf(filterStr) !== -1 + node.message.payload && + Base64Message.toUnicodeString(node.message.payload).toLowerCase().indexOf(filterStr) !== -1 return Boolean(messageMatches) } diff --git a/app/src/actions/clearTopic.ts b/app/src/actions/clearTopic.ts index 068662b..0c3e7df 100644 --- a/app/src/actions/clearTopic.ts +++ b/app/src/actions/clearTopic.ts @@ -48,6 +48,7 @@ export const clearTopic = (topic: q.TreeNode, recursive: boolean) => async payload: null, retain: true, qos: 0 as 0, + messageId: undefined, } // Rate limit deletion setTimeout(() => rendererEvents.emit(publishEvent, mqttMessage), 20 * idx) diff --git a/app/src/components/SettingsDrawer/BrokerStatistics.tsx b/app/src/components/SettingsDrawer/BrokerStatistics.tsx index 04b3c7c..c5c210d 100644 --- a/app/src/components/SettingsDrawer/BrokerStatistics.tsx +++ b/app/src/components/SettingsDrawer/BrokerStatistics.tsx @@ -123,8 +123,8 @@ function renderStat(tree: q.Tree, stat: Stats) { return null } - const str = node.message.value ? Base64Message.toUnicodeString(node.message.value) : '' - let value = node.message && node.message.value ? parseFloat(str) : NaN + const str = node.message.payload ? Base64Message.toUnicodeString(node.message.payload) : '' + let value = node.message && node.message.payload ? parseFloat(str) : NaN value = !isNaN(value) ? abbreviate(value) : str return ( diff --git a/app/src/components/Sidebar/MessageId.tsx b/app/src/components/Sidebar/MessageId.tsx new file mode 100644 index 0000000..4c600f3 --- /dev/null +++ b/app/src/components/Sidebar/MessageId.tsx @@ -0,0 +1,20 @@ +import React, { memo } from 'react' +import { Message } from '../../../../backend/src/Model' +import { Tooltip } from '@material-ui/core' + +export const MessageId = memo(function MessageId(props: { message: Message; addComma?: boolean }) { + const { message, addComma } = props + + if (!message.messageId) { + return null + } + + return ( + + + #msg: {message.messageId} + {addComma ? ', ' : ''} + + + ) +}) diff --git a/app/src/components/Sidebar/TopicPanel/TopicDeleteButton.tsx b/app/src/components/Sidebar/TopicPanel/TopicDeleteButton.tsx index ae447ff..c40fee8 100644 --- a/app/src/components/Sidebar/TopicPanel/TopicDeleteButton.tsx +++ b/app/src/components/Sidebar/TopicPanel/TopicDeleteButton.tsx @@ -8,7 +8,7 @@ export const TopicDeleteButton = (props: { deleteTopicAction: (node: q.TreeNode) => void }) => { const { node } = props - if (!node || !node.message || !node.message.value) { + if (!node || !node.message || !node.message.payload) { return null } return ( diff --git a/app/src/components/Sidebar/ValueRenderer/MessageHistory.tsx b/app/src/components/Sidebar/ValueRenderer/MessageHistory.tsx index 2b2dfcf..e3d9dbe 100644 --- a/app/src/components/Sidebar/ValueRenderer/MessageHistory.tsx +++ b/app/src/components/Sidebar/ValueRenderer/MessageHistory.tsx @@ -12,6 +12,7 @@ import { bindActionCreators } from 'redux' import { chartActions } from '../../../actions' import { connect } from 'react-redux' import CustomIconButton from '../../helper/CustomIconButton' +import { MessageId } from '../MessageId' const throttle = require('lodash.throttle') @@ -81,19 +82,25 @@ class MessageHistory extends React.PureComponent { const history = node.messageHistory.toArray() let previousMessage: q.Message | undefined = node.message const historyElements = [...history].reverse().map((message, idx) => { - const value = message.value ? Base64Message.toUnicodeString(message.value) : '' + const value = message.payload ? Base64Message.toUnicodeString(message.payload) : '' const element = { value, key: `${message.messageNumber}-${message.received}`, title: ( - - {previousMessage && previousMessage !== message ? ( - - (- - ) - - ) : null} +
+ + {previousMessage && previousMessage !== message ? ( + + (- + ) + + ) : null} +
+ +   + +
@@ -106,7 +113,7 @@ class MessageHistory extends React.PureComponent { }) const isMessagePlottable = - node.message && node.message.value && isPlottable(Base64Message.toUnicodeString(node.message.value)) + node.message && node.message.payload && isPlottable(Base64Message.toUnicodeString(node.message.payload)) return (
@@ -36,7 +37,7 @@ function ValuePanel(props: Props) { const { node, compareMessage } = props function renderViewOptions() { - if (!props.node || !props.node.message || !props.node.mqttMessage) { + if (!props.node || !props.node.message) { return null } @@ -46,7 +47,7 @@ function ValuePanel(props: Props) { - {props.node.mqttMessage.retain ? : null} + {props.node.message.retain ? : null} {messageMetaInfo()}
@@ -54,13 +55,16 @@ function ValuePanel(props: Props) { } function messageMetaInfo() { - if (!props.node || !props.node.message || !props.node.mqttMessage) { + if (!props.node || !props.node.message) { return null } return ( - QoS: {props.node.mqttMessage.qos} + + + {`QoS: ${props.node.message.qos}`} + @@ -82,8 +86,8 @@ function ValuePanel(props: Props) { ) const copyValue = - node && node.message && node.message.value ? ( - + node && node.message && node.message.payload ? ( + ) : null return ( diff --git a/app/src/components/Sidebar/ValueRenderer/ValueRenderer.tsx b/app/src/components/Sidebar/ValueRenderer/ValueRenderer.tsx index 704dd77..3a4f9ff 100644 --- a/app/src/components/Sidebar/ValueRenderer/ValueRenderer.tsx +++ b/app/src/components/Sidebar/ValueRenderer/ValueRenderer.tsx @@ -63,12 +63,12 @@ class ValueRenderer extends React.Component { } private renderRawMode(message: q.Message, compare?: q.Message) { - if (!message.value) { + if (!message.payload) { return } - const [value, valueLanguage] = this.convertMessage(message.value) + const [value, valueLanguage] = this.convertMessage(message.payload) const [compareStr, compareStrLanguage] = - compare && compare.value ? this.convertMessage(compare.value) : [undefined, undefined] + compare && compare.payload ? this.convertMessage(compare.payload) : [undefined, undefined] return (
@@ -95,12 +95,12 @@ class ValueRenderer extends React.Component { if (renderMode === 'raw') { return this.renderRawMode(message, compareWith) } - if (!message.value) { + if (!message.payload) { return null } - const compareValue = compareMessage.value || message.value - const [current, currentLanguage] = this.convertMessage(message.value) + const compareValue = compareMessage.payload || message.payload + const [current, currentLanguage] = this.convertMessage(message.payload) const [compare, compareLanguage] = this.convertMessage(compareValue) const language = currentLanguage === compareLanguage && compareLanguage === 'json' ? 'json' : undefined diff --git a/app/src/components/TopicPlot.tsx b/app/src/components/TopicPlot.tsx index e76a179..56c69d1 100644 --- a/app/src/components/TopicPlot.tsx +++ b/app/src/components/TopicPlot.tsx @@ -28,7 +28,7 @@ function filterUsingTimeRange(startTime: number | undefined, data: Array { - const value = message.value ? toPlottableValue(Base64Message.toUnicodeString(message.value)) : NaN + const value = message.payload ? toPlottableValue(Base64Message.toUnicodeString(message.payload)) : NaN return { x: message.received.getTime(), y: toPlottableValue(value) } }) .filter(data => !isNaN(data.y as any)) as any @@ -39,7 +39,7 @@ function nodeDotPathToHistory(startTime: number | undefined, history: q.MessageH .map((message: q.Message) => { let json = {} try { - json = message.value ? JSON.parse(Base64Message.toUnicodeString(message.value)) : {} + json = message.payload ? JSON.parse(Base64Message.toUnicodeString(message.payload)) : {} } catch (ignore) {} const value = dotProp.get(json, dotPath) diff --git a/app/src/components/Tree/TreeNode/TreeNodeTitle.tsx b/app/src/components/Tree/TreeNode/TreeNodeTitle.tsx index 9b32c4d..07d60a5 100644 --- a/app/src/components/Tree/TreeNode/TreeNodeTitle.tsx +++ b/app/src/components/Tree/TreeNode/TreeNodeTitle.tsx @@ -27,17 +27,17 @@ class TreeNodeTitle extends React.PureComponent { private truncatedMessage() { const limit = 400 - if (!this.props.treeNode.message || !this.props.treeNode.message.value) { + if (!this.props.treeNode.message || !this.props.treeNode.message.payload) { return '' } - const str = Base64Message.toUnicodeString(this.props.treeNode.message.value) + const str = Base64Message.toUnicodeString(this.props.treeNode.message.payload) return str.length > limit ? `${str.slice(0, limit)}…` : str } private renderValue() { return this.props.treeNode.message && - this.props.treeNode.message.value && + this.props.treeNode.message.payload && this.props.treeNode.message.length > 0 ? ( {' '} diff --git a/app/src/components/Tree/TreeNode/index.tsx b/app/src/components/Tree/TreeNode/index.tsx index 3dd17cc..5949fd0 100644 --- a/app/src/components/Tree/TreeNode/index.tsx +++ b/app/src/components/Tree/TreeNode/index.tsx @@ -81,7 +81,7 @@ function TreeNodeComponent(props: Props) { const mouseOver = useCallback( (event: React.MouseEvent) => { event.stopPropagation() - if (settings.get('selectTopicWithMouseOver') && treeNode && treeNode.message && treeNode.message.value) { + if (settings.get('selectTopicWithMouseOver') && treeNode && treeNode.message && treeNode.message.payload) { didSelectTopic() } }, diff --git a/backend/src/DataSource/DataSource.ts b/backend/src/DataSource/DataSource.ts index 971adb5..aff8e9c 100644 --- a/backend/src/DataSource/DataSource.ts +++ b/backend/src/DataSource/DataSource.ts @@ -1,7 +1,7 @@ import { DataSourceStateMachine } from './' import { MqttMessage } from '../../../events' -type MessageCallback = (topic: string, payload: Buffer) => void +type MessageCallback = (topic: string, payload: Buffer, packet: any) => void // A DataSource should automatically reconnect if connection was broken interface DataSource { diff --git a/backend/src/Model/Message.ts b/backend/src/Model/Message.ts index 1be9f2b..5b94304 100644 --- a/backend/src/Model/Message.ts +++ b/backend/src/Model/Message.ts @@ -1,8 +1,17 @@ import { Base64Message } from './Base64Message' +import { QoS } from '../DataSource/MqttSource' export interface Message { - value?: Base64Message + // mqtt based info + payload: Base64Message | null + messageId?: number + retain: boolean + qos: QoS + + // meta info length: number received: Date + + // Global message counter, not mqtt related messageNumber: number } diff --git a/backend/src/Model/Tree.ts b/backend/src/Model/Tree.ts index 15e6bb0..d3aa655 100644 --- a/backend/src/Model/Tree.ts +++ b/backend/src/Model/Tree.ts @@ -75,13 +75,7 @@ export class Tree extends TreeNode { public applyUnmergedChanges() { this.unmergedMessages.popAll().forEach(bufferedItem => { - const edges = bufferedItem.message.topic.split('/') - const node = TreeNodeFactory.fromEdgesAndValue( - edges, - bufferedItem.message.payload, - bufferedItem.received - ) - node.mqttMessage = bufferedItem.message + const node = TreeNodeFactory.fromMessage(bufferedItem.message, bufferedItem.received) if (!this.nodeFilter || this.nodeFilter(node)) { this.updateWithNode(node.firstNode()) diff --git a/backend/src/Model/TreeNode.ts b/backend/src/Model/TreeNode.ts index 7d8b6fe..1576b92 100644 --- a/backend/src/Model/TreeNode.ts +++ b/backend/src/Model/TreeNode.ts @@ -1,11 +1,10 @@ import { Destroyable } from './Destroyable' import { Edge, Message, RingBuffer, MessageHistory } from './' -import { EventDispatcher, MqttMessage } from '../../../events' +import { EventDispatcher } from '../../../events' export class TreeNode { public sourceEdge?: Edge public message?: Message - public mqttMessage?: MqttMessage public messageHistory: MessageHistory = new RingBuffer(20000, 100) public viewModel?: ViewModel public edges: { [s: string]: Edge } = {} @@ -105,7 +104,7 @@ export class TreeNode { } public hasMessage() { - return this.message && this.message.value && this.message.value.length !== 0 + return this.message && this.message.payload && this.message.length !== 0 } public destroy() { @@ -131,7 +130,6 @@ export class TreeNode { public unconnectedClone() { const node = new TreeNode() node.message = this.message - node.mqttMessage = this.mqttMessage node.messageHistory = this.messageHistory.clone() node.messages = this.messages node.lastUpdate = this.lastUpdate @@ -203,7 +201,6 @@ export class TreeNode { if (node.message) { this.setMessage(node.message) this.onMessage.dispatch(node.message) - this.mqttMessage = node.mqttMessage } this.removeFromTreeIfEmpty() @@ -236,7 +233,7 @@ export class TreeNode { public childTopics(): Array> { if (this.cachedChildTopics === undefined) { - const initialValue = this.message && this.message.value ? [this] : [] + const initialValue = this.message && this.message.payload ? [this] : [] this.cachedChildTopics = this.edgeArray .map(e => e.target.childTopics()) diff --git a/backend/src/Model/TreeNodeFactory.ts b/backend/src/Model/TreeNodeFactory.ts index f8e6f85..d1b2c52 100644 --- a/backend/src/Model/TreeNodeFactory.ts +++ b/backend/src/Model/TreeNodeFactory.ts @@ -1,6 +1,6 @@ -import { Base64Message } from './Base64Message' import { Destroyable } from './Destroyable' import { Edge, Tree, TreeNode } from './' +import { MqttMessage } from '../../../events' export abstract class TreeNodeFactory { private static messageCounter = 0 @@ -20,21 +20,23 @@ export abstract class TreeNodeFactory { node.sourceEdge!.target = node } - public static fromEdgesAndValue( - edgeNames: Array, - value?: Base64Message | null, + public static fromMessage( + mqttMessage: MqttMessage, receiveDate: Date = new Date() ): TreeNode { const node = new TreeNode() + const edges = mqttMessage.topic.split('/') + + mqttMessage.retain node.setMessage({ - value: value || undefined, - length: value ? value.length : 0, + ...mqttMessage, + length: mqttMessage.payload?.length ?? 0, received: receiveDate, messageNumber: this.messageCounter, }) this.messageCounter += 1 - this.insertNodeAtPosition(edgeNames, node) + this.insertNodeAtPosition(edges, node) return node } diff --git a/backend/src/Model/spec/Edge.spec.ts b/backend/src/Model/spec/Edge.spec.ts index dbb971c..c8a9e47 100644 --- a/backend/src/Model/spec/Edge.spec.ts +++ b/backend/src/Model/spec/Edge.spec.ts @@ -1,6 +1,7 @@ -import { Edge, TreeNodeFactory } from '../' -import { expect } from 'chai' import 'mocha' +import { expect } from 'chai' +import { Edge } from '../' +import { makeTreeNode } from './makeTreeNode' describe('Edge', () => { it('should contain a name', () => { @@ -9,8 +10,7 @@ describe('Edge', () => { }) it('firstEdge should retrieve the first edge', () => { - const topics = 'foo/bar/baz'.split('/') - const leaf = TreeNodeFactory.fromEdgesAndValue(topics, undefined) + const leaf = makeTreeNode('foo/bar/baz') const bazEdge = leaf.sourceEdge if (!bazEdge) { @@ -34,11 +34,8 @@ describe('Edge', () => { }) it('hash should include change if parents are different', () => { - const topics1 = 'foo/bar/baz'.split('/') - const bazEdge1 = TreeNodeFactory.fromEdgesAndValue(topics1, undefined).sourceEdge - - const topics2 = 'foo/foo/baz'.split('/') - const bazEdge2 = TreeNodeFactory.fromEdgesAndValue(topics2, undefined).sourceEdge + const bazEdge1 = makeTreeNode('foo/bar/baz').sourceEdge + const bazEdge2 = makeTreeNode('foo/foo/baz').sourceEdge if (!bazEdge1 || !bazEdge2) { throw Error('should not happen') diff --git a/backend/src/Model/spec/Tree.spec.ts b/backend/src/Model/spec/Tree.spec.ts index e5ea6b9..1ca5f86 100644 --- a/backend/src/Model/spec/Tree.spec.ts +++ b/backend/src/Model/spec/Tree.spec.ts @@ -1,18 +1,16 @@ import 'mocha' - -import { Tree, TreeNodeFactory } from '../' - import { expect } from 'chai' +import { Tree } from '../' +import { makeTreeNode } from './makeTreeNode' describe('Tree', () => { it('node can be merged into a tree', () => { const tree = new Tree() - - const topics = 'foo/bar'.split('/') - const leaf = TreeNodeFactory.fromEdgesAndValue(topics, undefined) + const leaf = makeTreeNode('foo/bar') tree.updateWithNode(leaf.firstNode()) const expectedNode = tree.findNode('foo/bar') + expect(expectedNode).to.eq(leaf) }) }) diff --git a/backend/src/Model/spec/TreeNode.findNode.spec.ts b/backend/src/Model/spec/TreeNode.findNode.spec.ts index bb26849..7026fd7 100644 --- a/backend/src/Model/spec/TreeNode.findNode.spec.ts +++ b/backend/src/Model/spec/TreeNode.findNode.spec.ts @@ -2,11 +2,11 @@ import 'mocha' import { TreeNodeFactory } from '../' import { expect } from 'chai' +import { makeTreeNode } from './makeTreeNode' describe('TreeNode.findNode', () => { it('findNode should retrieve node', () => { - const topics = 'foo/bar/baz'.split('/') - const leaf = TreeNodeFactory.fromEdgesAndValue(topics, undefined) + const leaf = makeTreeNode('foo/bar/baz') const root = leaf.firstNode() expect(root.sourceEdge).to.eq(undefined) diff --git a/backend/src/Model/spec/TreeNode.spec.ts b/backend/src/Model/spec/TreeNode.spec.ts index 2cd8495..4a31ae1 100644 --- a/backend/src/Model/spec/TreeNode.spec.ts +++ b/backend/src/Model/spec/TreeNode.spec.ts @@ -1,55 +1,51 @@ import 'mocha' -import { TreeNodeFactory } from '../' import { expect } from 'chai' import { Base64Message } from '../Base64Message' +import { makeTreeNode } from './makeTreeNode' describe('TreeNode', () => { - const number3 = Base64Message.fromString('3') - const number5 = Base64Message.fromString('5') it('firstNode should retrieve first node', () => { - const topics = 'foo/bar'.split('/') - const leaf = TreeNodeFactory.fromEdgesAndValue(topics, undefined) + const leaf = makeTreeNode('foo/bar') expect(leaf.firstNode().edges['foo']).to.not.eq(undefined) }) it('updateWithNode should update value', () => { const topics = 'foo/bar'.split('/') - const leaf = TreeNodeFactory.fromEdgesAndValue(topics, Base64Message.fromString('3')) - expect(Base64Message.toUnicodeString(leaf.message!.value!)).to.eq('3') - const updateLeave = TreeNodeFactory.fromEdgesAndValue(topics, Base64Message.fromString('5')) + const leaf = makeTreeNode('foo/bar', '3') + expect(Base64Message.toUnicodeString(leaf.message!.payload!)).to.eq('3') + + const updateLeave = makeTreeNode('foo/bar', '5') const root = leaf.firstNode() root.updateWithNode(updateLeave.firstNode()) expect(root.sourceEdge).to.eq(undefined) - expect(Base64Message.toUnicodeString(leaf.message!.value!)).to.eq('5') + expect(Base64Message.toUnicodeString(leaf.message!.payload!)).to.eq('5') }) it('updateWithNode should update intermediate nodes', () => { const topics1 = 'foo/bar/baz'.split('/') - const leaf = TreeNodeFactory.fromEdgesAndValue(topics1, Base64Message.fromString('3')) - expect(Base64Message.toUnicodeString(leaf.message!.value!)).to.eq('3') + const leaf = makeTreeNode('foo/bar/baz', '3') + expect(Base64Message.toUnicodeString(leaf.message!.payload!)).to.eq('3') const topics2 = 'foo/bar'.split('/') - const updateLeave = TreeNodeFactory.fromEdgesAndValue(topics2, Base64Message.fromString('5')) + const updateLeave = makeTreeNode('foo/bar', '5') + leaf.firstNode().updateWithNode(updateLeave.firstNode()) const barNode = leaf.firstNode().findNode('foo/bar') expect(barNode && barNode.sourceEdge && barNode.sourceEdge.name).to.eq('bar') - expect(Base64Message.toUnicodeString(barNode!.message!.value!)).to.eq('5') + expect(Base64Message.toUnicodeString(barNode!.message!.payload!)).to.eq('5') expect(leaf.sourceEdge && leaf.sourceEdge.name).to.eq('baz') - expect(Base64Message.toUnicodeString(leaf.message!.value!)).to.eq('3') + expect(Base64Message.toUnicodeString(leaf.message!.payload!)).to.eq('3') }) it('updateWithNode should add nodes to the tree', () => { - const topics1 = 'foo/bar'.split('/') - const leaf1 = TreeNodeFactory.fromEdgesAndValue(topics1, Base64Message.fromString('foo')) - - const topics2 = 'foo/bar/baz'.split('/') - const leaf2 = TreeNodeFactory.fromEdgesAndValue(topics2, Base64Message.fromString('bar')) + const leaf1 = makeTreeNode('foo/bar', 'foo') + const leaf2 = makeTreeNode('foo/bar/baz', 'bar') leaf1.firstNode().updateWithNode(leaf2.firstNode()) diff --git a/backend/src/Model/spec/TreeNodeFactory.spec.ts b/backend/src/Model/spec/TreeNodeFactory.spec.ts index 7d31000..5b69a8d 100644 --- a/backend/src/Model/spec/TreeNodeFactory.spec.ts +++ b/backend/src/Model/spec/TreeNodeFactory.spec.ts @@ -1,22 +1,17 @@ import 'mocha' - -import { TreeNodeFactory } from '../' import { expect } from 'chai' import { Base64Message } from '../Base64Message' +import { makeTreeNode } from './makeTreeNode' describe('TreeNodeFactory', () => { it('root node must not have a sourceEdge', () => { - const topic = 'foo/bar' - const edges = topic.split('/') - const leaf = TreeNodeFactory.fromEdgesAndValue(edges, undefined) + const leaf = makeTreeNode('foo/bar') expect(leaf.firstNode().sourceEdge).to.eq(undefined) }) it('should create node', () => { - const topic = 'foo/bar' - const edges = topic.split('/') - const node = TreeNodeFactory.fromEdgesAndValue(edges, Base64Message.fromString('5')) + const node = makeTreeNode('foo/bar', '5') if (!node.sourceEdge || !node.sourceEdge.source || !node.message) { expect.fail('should not happen') @@ -25,23 +20,21 @@ describe('TreeNodeFactory', () => { expect(node).to.not.eq(undefined) expect(node.sourceEdge.name).to.eq('bar') - expect(Base64Message.toUnicodeString(node.message.value!)).to.eq('5') + expect(Base64Message.toUnicodeString(node.message.payload!)).to.eq('5') const foo = node.firstNode().findNode('foo') expect(foo && foo.sourceEdge && foo.sourceEdge.name).to.eq('foo') }) it('node should contain edges in order', () => { - const topic = 'foo/bar/baz' - const edges = topic.split('/') - const node = TreeNodeFactory.fromEdgesAndValue(edges, Base64Message.fromString('5')) + const node = makeTreeNode('foo/bar/baz', '5') if (!node.sourceEdge || !node.sourceEdge.source || !node.message) { expect.fail('should not happen') return } - expect(Base64Message.toUnicodeString(node.message.value!)).to.eq('5') + expect(Base64Message.toUnicodeString(node.message.payload!)).to.eq('5') expect(node.sourceEdge.name).to.eq('baz') const barNode = node.sourceEdge.source diff --git a/backend/src/Model/spec/makeTreeNode.ts b/backend/src/Model/spec/makeTreeNode.ts new file mode 100644 index 0000000..d98e42b --- /dev/null +++ b/backend/src/Model/spec/makeTreeNode.ts @@ -0,0 +1,16 @@ +import { TreeNodeFactory } from '../' +import { Base64Message } from '../Base64Message' +import { TreeNode } from '../TreeNode' +import { MqttMessage } from '../../../../events' + +export function makeTreeNode(topic: string, message?: string): TreeNode { + const mqttMessage: MqttMessage = { + topic, + payload: message ? Base64Message.fromString(message) : null, + qos: 0, + retain: false, + messageId: undefined, + } + + return TreeNodeFactory.fromMessage(mqttMessage) +} diff --git a/backend/src/index.ts b/backend/src/index.ts index 48a0b2c..f78ad97 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -45,11 +45,13 @@ export class ConnectionManager { if (buffer.length > 20000) { buffer = buffer.slice(0, 20000) } + backendEvents.emit(messageEvent, { topic, payload: Base64Message.fromBuffer(buffer), qos: packet.qos, retain: packet.retain, + messageId: packet.messageId, }) }) } diff --git a/events/Events.ts b/events/Events.ts index 0c0d756..473e3e7 100644 --- a/events/Events.ts +++ b/events/Events.ts @@ -34,6 +34,8 @@ export interface MqttMessage { payload: Base64Message | null qos: 0 | 1 | 2 retain: boolean + // Set if QoS is > 0 on received messages + messageId: number | undefined } export function makePublishEvent(connectionId: string): Event {