Types are now bidirectional
It is still possible to define types as functions (Buffer => string for state topics, string => Buffer for command topics). Otherwise types have from and to properties. (Fixes #101)
This commit is contained in:
parent
2997ff8862
commit
ccd9bcd3b5
7 changed files with 64 additions and 38 deletions
|
|
@ -124,8 +124,8 @@ class App extends React.PureComponent<AppProps & Classes, AppState> {
|
|||
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<AppProps & Classes, AppState> {
|
|||
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() });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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<T> = {
|
||||
name: string,
|
||||
type: TopicType
|
||||
type: T
|
||||
}
|
||||
|
||||
export type Topic = {
|
||||
state?: StateCommand,
|
||||
command?: StateCommand,
|
||||
state?: StateCommand<StateTopicType>,
|
||||
command?: StateCommand<CommandTopicType>,
|
||||
defaultValue: string
|
||||
};
|
||||
export type Topics = Map<string, Topic>;
|
||||
|
|
@ -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<Topics>,
|
||||
|
|
|
|||
|
|
@ -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}]`)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -10,15 +10,3 @@ declare type Classes = {
|
|||
declare type State = Map<string,string>;
|
||||
|
||||
declare type Point = [number, number];
|
||||
|
||||
declare type Layer = {
|
||||
image: string,
|
||||
name: string,
|
||||
baseLayer?: boolean,
|
||||
defaultVisibility: "visible" | "hidden",
|
||||
opacity?: number,
|
||||
bounds: {
|
||||
topLeft: Point,
|
||||
bottomRight: Point
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue