diff --git a/src/components/App.js b/src/components/App.js index 818c481..b696647 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -124,8 +124,8 @@ class App extends React.PureComponent { for (let i in topics) { const topic = topics[i]; const stateTopic = this.topics[topic].state; - const parseVal = stateTopic ? stateTopic.type : null; - const val = parseVal == null ? message.toString() : parseVal(message); + const typeConversion = stateTopic?.type?.from ?? stateTopic?.type; + const val = (typeConversion ?? ((x) => x.toString()))(message); this.setMqttStateDebounced( {mqttState: Object.assign({}, merge(this.state.mqttState, { [topic]: val}))}); @@ -145,16 +145,16 @@ class App extends React.PureComponent { this.setState({drawerOpened: false}); } - changeState = (topic: string, value: string) => { + changeState = (topic: string, val: string) => { try { - if (this.topics[topic].command == null) { + const commandTopic = this.topics[topic].command; + if (commandTopic == null) { return; } - const rawTopic = this.topics[topic].command.name; - const transformValue = this.topics[topic].command.type; - const val = - transformValue == null ? value : transformValue(Buffer.from(value)); - this.state.mqttSend(rawTopic, Buffer.from(val)); + const rawTopic = commandTopic.name; + const typeConversion = commandTopic.type?.to ?? commandTopic.type; + const value = (typeConversion ?? Buffer.from)(val); + this.state.mqttSend(rawTopic, value); } catch (err) { this.setState({ error: err.toString() }); } diff --git a/src/components/ControlMap.js b/src/components/ControlMap.js index 231dd1b..b723831 100644 --- a/src/components/ControlMap.js +++ b/src/components/ControlMap.js @@ -6,7 +6,9 @@ import map from "lodash/map"; import filter from "lodash/filter"; import reduce from "lodash/reduce"; import MqttContext from "mqtt/context"; -import type { Controls, Control, UIControl, ControlUI } from "config/flowtypes"; +import type { + Controls, Control, UIControl, ControlUI, Layer +} from "config/flowtypes"; import { renderToString } from "react-dom/server"; export type Point = [number, number]; diff --git a/src/config/flowtypes.js b/src/config/flowtypes.js index be2091e..719b90b 100644 --- a/src/config/flowtypes.js +++ b/src/config/flowtypes.js @@ -1,16 +1,22 @@ // @flow import type { Icon } from "config/icon"; -export type TopicType = (msg: Buffer) => string; +export type TopicType = { + from: (msg: Buffer) => string, + to: (newstate: string) => Buffer +}; -export type StateCommand = { +export type StateTopicType = TopicType | ((msg: Buffer) => string); +export type CommandTopicType = TopicType | ((newstate: string) => Buffer); + +export type StateCommand = { name: string, - type: TopicType + type: T } export type Topic = { - state?: StateCommand, - command?: StateCommand, + state?: StateCommand, + command?: StateCommand, defaultValue: string }; export type Topics = Map; @@ -114,6 +120,17 @@ export type Space = { mqtt: string }; +export type Layer = { + image: string, + name: string, + baseLayer?: boolean, + defaultVisibility: "visible" | "hidden", + opacity?: number, + bounds: { + topLeft: Point, + bottomRight: Point + } +}; export type Config = { space: Space, topics: Topics | Array, diff --git a/src/config/types.js b/src/config/types.js index 478108d..7cf4765 100644 --- a/src/config/types.js +++ b/src/config/types.js @@ -1,13 +1,22 @@ // @flow import type { TopicType } from "config/flowtypes"; import at from "lodash/at"; +import set from "lodash/set"; -export const string: TopicType = (msg: Buffer) => msg.toString(); +export const string: TopicType = { + from: (msg: Buffer) => msg.toString(), + to: (msg: string) => Buffer.from(msg) +}; export const json = (path: string, innerType?: TopicType): TopicType => { - const parseAgain = innerType == null ? (x) => x.toString() : innerType; - return (msg) => parseAgain(Buffer.from( - at(JSON.parse(msg.toString()), path)[0].toString())); + const parseAgain = innerType?.from ?? ((x) => x.toString()); + const parseFirst = innerType?.to ?? ((x) => Buffer.from(x)); + return { + from: (msg) => parseAgain(Buffer.from( + at(JSON.parse(msg.toString()), path)[0].toString())), + to: (msg) => Buffer.from( + JSON.serialize(set({}, path, parseFirst(msg).toString()))) + }; }; export type TypeOptionParam = { otherwise?: string, [string]: string }; @@ -16,13 +25,17 @@ export const option = (values: TypeOptionParam): TopicType => { if (values.otherwise != null) { return values.otherwise; } else { - throw new Error( - `Value ${x.toString()} cannot be mapped by the option parameters given` - ); + return x; } }; const mapVal = (x) => (values[x] != null ? values[x] : defaultValue(x)); - return (x) => mapVal(x.toString()); + return { + from: (x) => mapVal(x.toString()), + to: (x) => Buffer.from(mapVal(x)) + }; }; -export const jsonArray = (msg: Buffer) => JSON.parse(msg.toString()).join(", "); +export const jsonArray = { + from: (msg: Buffer) => JSON.parse(msg.toString()).join(", "), + to: (msg: string) => Buffer.from(`[${msg}]`) +}; diff --git a/src/index.jsx b/src/index.jsx index 60400b8..44740ce 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -1,7 +1,7 @@ // @flow import "core-js/stable"; import "regenerator-runtime/runtime"; -import "../node_modules/leaflet/dist/leaflet.css" +import "../node_modules/leaflet/dist/leaflet.css"; import React from "react"; import ReactDOM from "react-dom"; diff --git a/types/types.js b/types/types.js index 5503e1a..60d5691 100644 --- a/types/types.js +++ b/types/types.js @@ -10,15 +10,3 @@ declare type Classes = { declare type State = Map; declare type Point = [number, number]; - -declare type Layer = { - image: string, - name: string, - baseLayer?: boolean, - defaultVisibility: "visible" | "hidden", - opacity?: number, - bounds: { - topLeft: Point, - bottomRight: Point - } -}; diff --git a/webpack.config.js b/webpack.config.js index 89d6f9a..a2b9295 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -41,7 +41,13 @@ module.exports = env => ({ }, plugins: [ new CleanWebpackPlugin(), - new WebpackShellPlugin({onBuildStart:preBuildScripts}), + new WebpackShellPlugin({ + onBuildStart: { + scripts: preBuildScripts, + blocking: true, + parallel: false + } + }), new HtmlWebpackPlugin({ title: 'Space Map', template: 'index.ejs'