[UNSTABLE] Pull out more legacy junk. V. unstable.

pull/1446/head
Rick Carlino 2019-09-17 14:26:19 -05:00
parent 2aa84d264d
commit 69ff481f91
14 changed files with 47 additions and 171 deletions

View File

@ -30,10 +30,6 @@ module Logs
def validate
add_error :log, :private, BAD_WORDS if has_bad_words
# I think this was here for legacy reasons and can be removed.
# Delete this comment if no log issues are noted after 25 MAR 19. - RC
# add_error :device, :no_id, "ID of device can't be nil" unless device.id
@log = Log.new(clean_inputs)
@log.validate!
end

View File

@ -29,15 +29,12 @@ import {
onPublicBroadcast,
onReconnect,
} from "../../connect_device";
import { onLogs } from "../../log_handlers";
import { Actions, Content } from "../../../constants";
import { Log } from "farmbot/dist/resources/api_resources";
import { ALLOWED_CHANNEL_NAMES, ALLOWED_MESSAGE_TYPES, Farmbot } from "farmbot";
import { dispatchNetworkUp, dispatchNetworkDown } from "../../index";
import { getDevice } from "../../../device";
import { fakeState } from "../../../__test_support__/fake_state";
import { talk } from "browser-speech";
import { globalQueue } from "../../batch_queue";
import { MessageType } from "../../../sequences/interfaces";
import { FbjsEventName } from "farmbot/dist/constants";
import { info, error, success, warning, fun, busy } from "../../../toast/toast";
@ -169,7 +166,6 @@ describe("bothUp()", () => {
it("marks MQTT and API as up", () => {
bothUp();
expect(dispatchNetworkUp).toHaveBeenCalledWith("user.mqtt", ANY_NUMBER);
expect(dispatchNetworkUp).toHaveBeenCalledWith("bot.mqtt", ANY_NUMBER);
});
});
@ -236,28 +232,6 @@ describe("onMalformed()", () => {
});
});
describe("onLogs", () => {
it("Calls `networkUp` when good logs come in", () => {
const fn = onLogs(jest.fn(), fakeState);
const log = fakeLog(MessageType.error, []);
log.message = "bot xyz is offline";
fn(log);
globalQueue.maybeWork();
expect(dispatchNetworkDown)
.toHaveBeenCalledWith("bot.mqtt", ANY_NUMBER);
});
it("handles log fields correctly", () => {
const fn = onLogs(jest.fn(), fakeState);
const log = fakeLog(MessageType.info, []);
log.message = "online";
// tslint:disable-next-line:no-any
(log as any).meta = { y: 200 };
fn(log);
expect(log).toEqual(expect.objectContaining({ message: "online", y: 200 }));
});
});
describe("onPublicBroadcast", () => {
const expectBroadcastLog = () =>
expect(console.log).toHaveBeenCalledWith(

View File

@ -41,15 +41,15 @@ const resetStats = () => {
};
describe("dispatchNetworkUp", () => {
const NOW_UP = networkUp("bot.mqtt", NOW.getTime());
const LATER_UP = networkUp("bot.mqtt", LONGER_TIME_LATER);
const NOW_UP = networkUp("user.mqtt", NOW.getTime());
const LATER_UP = networkUp("user.mqtt", LONGER_TIME_LATER);
it("calls redux directly", () => {
dispatchNetworkUp("bot.mqtt", NOW.getTime());
dispatchNetworkUp("user.mqtt", NOW.getTime());
expect(store.dispatch).toHaveBeenLastCalledWith(NOW_UP);
dispatchNetworkUp("bot.mqtt", SHORT_TIME_LATER);
dispatchNetworkUp("user.mqtt", SHORT_TIME_LATER);
expect(store.dispatch).toHaveBeenLastCalledWith(NOW_UP);
dispatchNetworkUp("bot.mqtt", LONGER_TIME_LATER);
dispatchNetworkUp("user.mqtt", LONGER_TIME_LATER);
expect(store.dispatch).toHaveBeenLastCalledWith(LATER_UP);
});
});

View File

@ -4,19 +4,15 @@ jest.mock("../index", () => ({
dispatchQosStart: jest.fn(),
pingOK: jest.fn()
}));
const ANY_NUMBER = expect.any(Number);
const mockTimestamp = 0;
jest.mock("../../util", () => ({ timestamp: () => mockTimestamp }));
import {
readPing,
markStale,
markActive,
startPinging,
PING_INTERVAL
} from "../ping_mqtt";
import { Farmbot, RpcRequest, RpcRequestBodyItem } from "farmbot";
import { dispatchNetworkDown, dispatchNetworkUp } from "../index";
import { FarmBotInternalConfig } from "farmbot/dist/config";
const state: Partial<FarmBotInternalConfig> = {
@ -44,18 +40,6 @@ function fakeBot(): Farmbot {
return fb as Farmbot;
}
function expectStale() {
expect(dispatchNetworkDown)
.toHaveBeenCalledWith("bot.mqtt", ANY_NUMBER);
}
function expectActive() {
expect(dispatchNetworkUp)
.toHaveBeenCalledWith("bot.mqtt", ANY_NUMBER);
expect(dispatchNetworkUp)
.toHaveBeenCalledWith("user.mqtt", ANY_NUMBER);
}
describe("ping util", () => {
it("reads LAST_PING_(IN|OUT)", () => {
const bot = fakeBot();
@ -63,16 +47,6 @@ describe("ping util", () => {
expect(readPing(bot, "out")).toEqual(456);
});
it("marks the bot's connection to MQTT as 'stale'", () => {
markStale();
expectStale();
});
it("marks the bot's connection to MQTT as 'active'", () => {
markActive();
expectActive();
});
it("binds event handlers with startPinging()", (done) => {
const bot = fakeBot();
startPinging(bot);

View File

@ -4,6 +4,7 @@ import { resourceReady } from "../../sync/actions";
describe("Connectivity Reducer - RESOURCE_READY", () => {
it("handles `undefined` status", () => {
pending("I want this to go away permanently - RC");
const device = fakeDevice();
device.body.last_saw_mq = "Tue, 03 Oct 2017 09:00:00 -0500";
const action = resourceReady("Device", device);

View File

@ -1,30 +1,30 @@
import { computeBestTime, getStatus } from "../reducer_support";
import moment from "moment";
import { ConnectionStatus } from "../interfaces";
import { getStatus } from "../reducer_support";
// import moment from "moment";
// import { ConnectionStatus } from "../interfaces";
// RELEVANT:
// https://en.wikipedia.org/wiki/Now_and_Later
const NOW = "Tue, 03 Oct 2017 09:00:00 -0500";
const LATER = "Wed, 04 Oct 2017 09:00:00 -0500";
// const LATER = "Wed, 04 Oct 2017 09:00:00 -0500";
const LATER_JSON = moment(LATER).toDate().getTime();
// const LATER_JSON = moment(LATER).toDate().getTime();
const NOW_UNIX = (new Date(NOW)).getTime();
describe("computeBestTime()", () => {
const STUB: ConnectionStatus = { state: "down", at: NOW_UNIX };
// describe("computeBestTime()", () => {
// const STUB: ConnectionStatus = { state: "down", at: NOW_UNIX };
it("returns same input when `last_saw_mq` is unavailable", () => {
expect(computeBestTime(undefined, undefined)).toBe(undefined);
expect(computeBestTime(STUB, undefined)).toBe(STUB);
const hmm = computeBestTime(undefined, LATER);
expect(hmm && hmm.at).toEqual(LATER_JSON);
});
// it("returns same input when `last_saw_mq` is unavailable", () => {
// expect(computeBestTime(undefined, undefined)).toBe(undefined);
// expect(computeBestTime(STUB, undefined)).toBe(STUB);
// const hmm = computeBestTime(undefined, LATER);
// expect(hmm && hmm.at).toEqual(LATER_JSON);
// });
it("computes best time when enough information is present", () => {
const expected: ConnectionStatus = { state: "down", at: LATER_JSON };
expect(computeBestTime(STUB, LATER)).toEqual(expected);
});
});
// it("computes best time when enough information is present", () => {
// const expected: ConnectionStatus = { state: "down", at: LATER_JSON };
// expect(computeBestTime(STUB, LATER)).toEqual(expected);
// });
// });
describe("getStatus()", () => {
it("returns 'down' when not given enough data", () => {

View File

@ -100,7 +100,8 @@ export const batchInitResources =
export const bothUp = () => {
dispatchNetworkUp("user.mqtt", now());
dispatchNetworkUp("bot.mqtt", now());
// WHO IS USING THIS? Best if we let the ping util handle it now.
// dispatchNetworkUp(" bot.mqtt", now());
};
export function readStatus() {

View File

@ -18,6 +18,9 @@ export const networkUptimeThrottleStats: Record<Edge, number> = {
};
function shouldThrottle(edge: Edge, now: number): boolean {
if (edge === "bot.mqtt") {
return true;
}
const then = networkUptimeThrottleStats[edge];
const diff = now - then;
return diff < SLOWDOWN_TIME;

View File

@ -6,50 +6,15 @@ import {
initLog
} from "./connect_device";
import { GetState } from "../redux/interfaces";
import { dispatchNetworkDown } from ".";
import { Log } from "farmbot/dist/resources/api_resources";
import { globalQueue } from "./batch_queue";
import { isUndefined, get } from "lodash";
import { MessageType } from "../sequences/interfaces";
import { now } from "../devices/connectivity/qos";
const LEGACY_META_KEY_NAMES: (keyof Log)[] = [
"type",
"x",
"y",
"z",
"verbosity",
"major_version",
"minor_version"
];
/** Copy fields from `log.meta` into `log`. */
function legacyKeyTransformation(log: Log, key: keyof Log) {
/** Attempt to find field in `log`. */
if (isUndefined(log[key])) {
/** Attempt to find field in `log.meta`. */
const metaValue: Log[typeof key] = get(log, ["meta", key], undefined);
// TODO: Fix this typing (expects `never` instead of `Log[typeof key]`).
log[key] = metaValue as never;
}
}
export const onLogs =
(_dispatch: Function, getState: GetState) => (msg: Log) => {
if (isLog(msg)) {
LEGACY_META_KEY_NAMES.map(key => legacyKeyTransformation(msg, key));
actOnChannelName(msg, "toast", showLogOnScreen);
actOnChannelName(msg, "espeak", speakLogAloud(getState));
const log = initLog(msg).payload;
log.kind == "Log" && globalQueue.push(log);
// CORRECT SOLUTION: Give each device its own topic for publishing
// MQTT last will message.
// FAST SOLUTION: We would need to re-publish FBJS and FBOS to
// change topic structure. Instead, we will use
// inband signalling (for now).
// TODO: Make a `bot/device_123/offline` channel.
const died =
msg.message.includes("is offline") && msg.type === MessageType.error;
died && dispatchNetworkDown("bot.mqtt", now());
}
};

View File

@ -23,19 +23,10 @@ export function readPing(bot: Farmbot, direction: Direction): number | undefined
return isNumber(val) ? val : undefined;
}
export function markStale() {
dispatchNetworkDown("bot.mqtt", now());
}
export function markActive() {
dispatchNetworkUp("user.mqtt", now());
dispatchNetworkUp("bot.mqtt", now());
}
export function sendOutboundPing(bot: Farmbot) {
const id = uuid();
const ok = () => pingOK(id, now()); markActive();
const no = () => pingNO(id, now()); markStale();
const ok = () => pingOK(id, now());
const no = () => pingNO(id, now());
dispatchQosStart(id);
bot.ping().then(ok, no);
}

View File

@ -1,10 +1,6 @@
import { generateReducer } from "../redux/generate_reducer";
import { Actions } from "../constants";
import { ConnectionState, EdgeStatus } from "./interfaces";
import { computeBestTime } from "./reducer_support";
import { TaggedDevice } from "farmbot";
import { SyncBodyContents } from "../sync/actions";
import { arrayUnwrap } from "../resources/util";
import { startPing, completePing, failPing } from "../devices/connectivity/qos";
export const DEFAULT_STATE: ConnectionState = {
@ -37,6 +33,7 @@ export let connectivityReducer =
.add<PingResultPayload>(Actions.PING_OK, (s, { payload }) => {
s.pings = completePing(s.pings, payload.id, payload.at);
maybeTransition(s, "up", payload.at);
console.log("TODO: Mark `user.mqtt` as up");
return s;
})
.add<PingResultPayload>(Actions.PING_NO, (s, { payload }) => {
@ -50,11 +47,4 @@ export let connectivityReducer =
}
s.uptime[payload.name] = payload.status;
return s;
})
.add<SyncBodyContents<TaggedDevice>>(Actions.RESOURCE_READY, (s, a) => {
const d = arrayUnwrap(a.payload.body);
if (d && d.kind === "Device") {
s.uptime["bot.mqtt"] = computeBestTime(s.uptime["bot.mqtt"], d && d.body.last_saw_mq);
}
return s;
});

View File

@ -1,26 +1,5 @@
import { ConnectionStatus } from "./interfaces";
import m from "moment";
import { isString } from "lodash";
export function getStatus(cs: ConnectionStatus | undefined): "up" | "down" {
return (cs && cs.state) || "down";
}
/** USE CASE: We have numerous, possibly duplicate sources of information
* that represent `last_saw_mq`. One came from the API and another (possibly)
* came from the MQ directly to the browser. This function determines which of
* the two is most relevant. It is a heuristic process that gives up when
* unable to make a determination. */
export function computeBestTime(cs: ConnectionStatus | undefined,
lastSawMq: string | undefined): ConnectionStatus | undefined {
const left = m(cs ? cs.at : lastSawMq);
const right = m(lastSawMq);
// Only use the `last_saw_mq` time if it is more recent than the local
// timestamp.
// don't bother guessing if info is unavailable
const guess: ConnectionStatus = {
at: Math.max(left.toDate().getTime(), right.toDate().getTime()),
state: getStatus(cs)
};
return isString(lastSawMq) ? guess : cs;
}

View File

@ -107,6 +107,7 @@ describe("botReducer", () => {
});
it("stashes/unstashes sync status based on connectivity", () => {
pending("Might not be required anymore with new ping system");
const step1 = initialState();
step1.statusStash = "booting";
step1.hardware.informational_settings.sync_status = "synced";

View File

@ -147,19 +147,20 @@ export let botReducer = generateReducer<BotState>(initialState())
unstash(s);
return s;
})
.add<EdgeStatus>(Actions.NETWORK_EDGE_CHANGE, (s, a) => {
const { name, status } = a.payload;
switch ((name === "bot.mqtt") && status.state) {
case "down":
stash(s);
s.hardware.informational_settings.sync_status = undefined;
break;
case "up":
const currentState = s.connectivity.uptime["bot.mqtt"];
// Going from "down" to "up"
const backOnline = currentState && currentState.state === "down";
backOnline && unstash(s);
}
.add<EdgeStatus>(Actions.NETWORK_EDGE_CHANGE, (s, _a) => {
// const { name, status } = a.payload;
console.log("Possible bug culprit here");
// switch ((name === "bot.mqtt") && status.state) {
// case "down":
// stash(s);
// s.hardware.informational_settings.sync_status = undefined;
// break;
// case "up":
// const currentState = s.connectivity.uptime["bot.mqtt"];
// // Going from "down" to "up"
// const backOnline = currentState && currentState.state === "down";
// backOnline && unstash(s);
// }
return s;
});