[UNSTABLE] Pull out more legacy junk. V. unstable.
parent
2aa84d264d
commit
69ff481f91
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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", () => {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue