Introduce NodeMonitoringStateResponse to get rid of some any

This commit is contained in:
baldo 2022-08-24 18:20:49 +02:00
parent 672369d419
commit 00d93c33b4
4 changed files with 100 additions and 48 deletions

View file

@ -11,23 +11,22 @@ import {
JSONObject, JSONObject,
MonitoringResponse, MonitoringResponse,
MonitoringToken, MonitoringToken,
NodeMonitoringStateResponse,
toMonitoringResponse, toMonitoringResponse,
} from "../types"; } from "../types";
const isValidToken = forConstraint(CONSTRAINTS.token, false); const isValidToken = forConstraint(CONSTRAINTS.token, false);
// FIXME: Get rid of any async function doGetAll(
async function doGetAll(req: Request): Promise<{ total: number; result: any }> { req: Request
): Promise<{ total: number; result: NodeMonitoringStateResponse[] }> {
const restParams = await Resources.getValidRestParams("list", null, req); const restParams = await Resources.getValidRestParams("list", null, req);
const { monitoringStates, total } = await MonitoringService.getAll( const { monitoringStates, total } = await MonitoringService.getAll(
restParams restParams
); );
return { return {
total, total,
result: monitoringStates.map((state) => { result: monitoringStates,
state.mapId = state.mac.toLowerCase().replace(/:/g, "");
return state;
}),
}; };
} }

View file

@ -22,7 +22,9 @@ import {
Hostname, Hostname,
isBoolean, isBoolean,
isDomain, isDomain,
isMailType,
isMonitoringSortField, isMonitoringSortField,
isMonitoringState,
isOnlineState, isOnlineState,
isPlainObject, isPlainObject,
isSite, isSite,
@ -30,12 +32,17 @@ import {
isUndefined, isUndefined,
JSONValue, JSONValue,
MAC, MAC,
MailId,
MailType, MailType,
MapId,
mapIdFromMAC,
MonitoringSortField, MonitoringSortField,
MonitoringState, MonitoringState,
MonitoringToken, MonitoringToken,
NodeId, NodeId,
NodeMonitoringStateResponse,
NodeStateData, NodeStateData,
NodeStateId,
OnlineState, OnlineState,
parseJSON, parseJSON,
RunResult, RunResult,
@ -55,13 +62,13 @@ import {
} from "../utils/time"; } from "../utils/time";
type NodeStateRow = { type NodeStateRow = {
id: number; id: NodeStateId;
created_at: UnixTimestampSeconds; created_at: UnixTimestampSeconds;
domain: Domain | null; domain: Domain | null;
hostname: Hostname | null; hostname: Hostname | null;
import_timestamp: UnixTimestampSeconds; import_timestamp: UnixTimestampSeconds;
last_seen: UnixTimestampSeconds; last_seen: UnixTimestampSeconds;
last_status_mail_sent: string | null; last_status_mail_sent: UnixTimestampSeconds | null;
last_status_mail_type: string | null; last_status_mail_type: string | null;
mac: MAC; mac: MAC;
modified_at: UnixTimestampSeconds; modified_at: UnixTimestampSeconds;
@ -356,7 +363,7 @@ export function parseNodesJson(body: string): NodesParsingResult {
} }
async function updateSkippedNode( async function updateSkippedNode(
id: NodeId, id: NodeStateId,
node?: StoredNode node?: StoredNode
): Promise<RunResult> { ): Promise<RunResult> {
return await db.run( return await db.run(
@ -370,7 +377,7 @@ async function updateSkippedNode(
async function sendMonitoringMailsBatched( async function sendMonitoringMailsBatched(
name: string, name: string,
mailType: MailType, mailType: MailType,
findBatchFun: () => Promise<any[]> findBatchFun: () => Promise<NodeStateRow[]>
): Promise<void> { ): Promise<void> {
Logger.tag("monitoring", "mail-sending").debug( Logger.tag("monitoring", "mail-sending").debug(
'Sending "%s" mails...', 'Sending "%s" mails...',
@ -477,8 +484,8 @@ async function sendOnlineAgainMails(
await sendMonitoringMailsBatched( await sendMonitoringMailsBatched(
"online again", "online again",
MailType.MONITORING_ONLINE_AGAIN, MailType.MONITORING_ONLINE_AGAIN,
async (): Promise<any[]> => async (): Promise<NodeStateRow[]> =>
await db.all( await db.all<NodeStateRow>(
"SELECT * FROM node_state " + "SELECT * FROM node_state " +
"WHERE modified_at < ? AND state = ? AND last_status_mail_type IN (" + "WHERE modified_at < ? AND state = ? AND last_status_mail_type IN (" +
"'monitoring-offline-1', 'monitoring-offline-2', 'monitoring-offline-3'" + "'monitoring-offline-1', 'monitoring-offline-2', 'monitoring-offline-3'" +
@ -497,7 +504,7 @@ async function sendOfflineMails(
await sendMonitoringMailsBatched( await sendMonitoringMailsBatched(
"offline " + mailNumber, "offline " + mailNumber,
mailType, mailType,
async (): Promise<any[]> => { async (): Promise<NodeStateRow[]> => {
const previousType = const previousType =
mailNumber === 1 mailNumber === 1
? "monitoring-online-again" ? "monitoring-online-again"
@ -510,7 +517,7 @@ async function sendOfflineMails(
const schedule = MONITORING_OFFLINE_MAILS_SCHEDULE[mailNumber]; const schedule = MONITORING_OFFLINE_MAILS_SCHEDULE[mailNumber];
const scheduledTimeBefore = subtract(now(), schedule); const scheduledTimeBefore = subtract(now(), schedule);
return await db.all( return await db.all<NodeStateRow>(
"SELECT * FROM node_state " + "SELECT * FROM node_state " +
"WHERE modified_at < ? AND state = ? AND (last_status_mail_type = ?" + "WHERE modified_at < ? AND state = ? AND (last_status_mail_type = ?" +
allowNull + allowNull +
@ -667,10 +674,33 @@ async function retrieveNodeInformationForUrls(
}; };
} }
// FIXME: Replace any[] by type. function toResponse(row: NodeStateRow): NodeMonitoringStateResponse {
// TODO: Handle conversion errors.
return {
id: row.id,
created_at: row.created_at,
domain: row.domain || undefined,
hostname: row.hostname || undefined,
import_timestamp: row.import_timestamp,
last_seen: row.last_seen,
last_status_mail_sent: row.last_status_mail_sent || undefined,
last_status_mail_type: isMailType(row.last_status_mail_type)
? row.last_status_mail_type
: undefined,
mac: row.mac,
modified_at: row.modified_at,
monitoring_state: isMonitoringState(row.monitoring_state)
? row.monitoring_state
: undefined,
site: row.site || undefined,
state: isOnlineState(row.state) ? row.state : OnlineState.OFFLINE,
mapId: mapIdFromMAC(row.mac),
};
}
export async function getAll( export async function getAll(
restParams: RestParams restParams: RestParams
): Promise<{ total: number; monitoringStates: any[] }> { ): Promise<{ total: number; monitoringStates: NodeMonitoringStateResponse[] }> {
const filterFields = [ const filterFields = [
"hostname", "hostname",
"mac", "mac",
@ -695,12 +725,15 @@ export async function getAll(
filterFields filterFields
); );
const monitoringStates = await db.all( const monitoringStates = await db.all<NodeStateRow>(
"SELECT * FROM node_state WHERE " + filter.query, "SELECT * FROM node_state WHERE " + filter.query,
filter.params filter.params
); );
return { monitoringStates, total }; return {
monitoringStates: monitoringStates.map(toResponse),
total,
};
} }
export async function getByMacs( export async function getByMacs(
@ -877,7 +910,7 @@ async function deleteNeverOnlineNodesBefore(
const placeholders = macs.map(() => "?").join(","); const placeholders = macs.map(() => "?").join(",");
const rows: { mac: MAC }[] = await db.all( const rows = await db.all<NodeStateRow>(
`SELECT * FROM node_state WHERE mac IN (${placeholders})`, `SELECT * FROM node_state WHERE mac IN (${placeholders})`,
macs macs
); );

View file

@ -368,6 +368,12 @@ export const isFastdKey = toIsNewtype(isString, "" as FastdKey);
export type MAC = string & { readonly __tag: unique symbol }; export type MAC = string & { readonly __tag: unique symbol };
export const isMAC = toIsNewtype(isString, "" as MAC); export const isMAC = toIsNewtype(isString, "" as MAC);
export type MapId = string & { readonly __tag: unique symbol };
export const isMapId = toIsNewtype(isString, "" as MapId);
export function mapIdFromMAC(mac: MAC): MapId {
return mac.toLowerCase().replace(/:/g, "") as MapId;
}
export type DurationSeconds = number & { readonly __tag: unique symbol }; export type DurationSeconds = number & { readonly __tag: unique symbol };
export const isDurationSeconds = toIsNewtype(isNumber, NaN as DurationSeconds); export const isDurationSeconds = toIsNewtype(isNumber, NaN as DurationSeconds);
@ -572,6 +578,49 @@ export function isMonitoringResponse(arg: unknown): arg is MonitoringResponse {
); );
} }
export type NodeStateId = number & { readonly __tag: unique symbol };
export const isNodeStateId = toIsNewtype(isNumber, 0 as NodeStateId);
export type NodeMonitoringStateResponse = {
id: NodeStateId;
created_at: UnixTimestampSeconds;
domain?: Domain;
hostname?: Hostname;
import_timestamp: UnixTimestampSeconds;
last_seen: UnixTimestampSeconds;
last_status_mail_sent?: UnixTimestampSeconds;
last_status_mail_type?: MailType;
mac: MAC;
modified_at: UnixTimestampSeconds;
monitoring_state?: MonitoringState;
site?: Site;
state: OnlineState;
mapId: MapId;
};
export type MailId = number & { readonly __tag: unique symbol };
export const isMailId = toIsNewtype(isNumber, NaN as MailId);
export type MailData = JSONObject;
export enum MailType {
MONITORING_OFFLINE_1 = "monitoring-offline-1",
MONITORING_OFFLINE_2 = "monitoring-offline-2",
MONITORING_OFFLINE_3 = "monitoring-offline-3",
MONITORING_ONLINE_AGAIN = "monitoring-online-again",
MONITORING_CONFIRMATION = "monitoring-confirmation",
}
export const isMailType = toIsEnum(MailType);
export type Mail = {
id: MailId;
email: MailType;
sender: EmailAddress;
recipient: EmailAddress;
data: MailData;
failures: number;
};
// noinspection JSUnusedGlobalSymbols // noinspection JSUnusedGlobalSymbols
enum NodeSortFieldEnum { enum NodeSortFieldEnum {
HOSTNAME = "hostname", HOSTNAME = "hostname",

View file

@ -2,9 +2,6 @@ import {
CreateOrUpdateNode, CreateOrUpdateNode,
Domain, Domain,
DomainSpecificNodeResponse, DomainSpecificNodeResponse,
EmailAddress,
isNumber,
JSONObject,
MonitoringResponse, MonitoringResponse,
MonitoringState, MonitoringState,
MonitoringToken, MonitoringToken,
@ -13,8 +10,6 @@ import {
OnlineState, OnlineState,
Site, Site,
StoredNode, StoredNode,
toIsEnum,
toIsNewtype,
} from "../shared/types"; } from "../shared/types";
export * from "./config"; export * from "./config";
@ -98,27 +93,3 @@ export function toMonitoringResponse(node: StoredNode): MonitoringResponse {
export type NodeSecrets = { export type NodeSecrets = {
monitoringToken?: MonitoringToken; monitoringToken?: MonitoringToken;
}; };
export type MailId = number & { readonly __tag: unique symbol };
export const isMailId = toIsNewtype(isNumber, NaN as MailId);
export type MailData = JSONObject;
export enum MailType {
MONITORING_OFFLINE_1 = "monitoring-offline-1",
MONITORING_OFFLINE_2 = "monitoring-offline-2",
MONITORING_OFFLINE_3 = "monitoring-offline-3",
MONITORING_ONLINE_AGAIN = "monitoring-online-again",
MONITORING_CONFIRMATION = "monitoring-confirmation",
}
export const isMailType = toIsEnum(MailType);
export type Mail = {
id: MailId;
email: MailType;
sender: EmailAddress;
recipient: EmailAddress;
data: MailData;
failures: number;
};