Make node filename parsing more explicit and add stronger typing.

This commit is contained in:
baldo 2022-07-28 14:09:46 +02:00
parent 779c072ac7
commit d2ca8ed55b
2 changed files with 26 additions and 21 deletions

View file

@ -176,7 +176,6 @@ async function storeNodeInformation(nodeData: ParsedNode, node: StoredNode): Pro
const isValidMac = forConstraint(CONSTRAINTS.node.mac, false); const isValidMac = forConstraint(CONSTRAINTS.node.mac, false);
// TODO: Use sparkson for JSON parsing.
export function parseNode(importTimestamp: UnixTimestampSeconds, nodeData: any): ParsedNode { export function parseNode(importTimestamp: UnixTimestampSeconds, nodeData: any): ParsedNode {
if (!_.isPlainObject(nodeData)) { if (!_.isPlainObject(nodeData)) {
throw new Error( throw new Error(
@ -249,7 +248,6 @@ export function parseNode(importTimestamp: UnixTimestampSeconds, nodeData: any):
}; };
} }
// TODO: Use sparkson for JSON parsing.
export function parseNodesJson(body: string): NodesParsingResult { export function parseNodesJson(body: string): NodesParsingResult {
Logger.tag('monitoring', 'information-retrieval').debug('Parsing nodes.json...'); Logger.tag('monitoring', 'information-retrieval').debug('Parsing nodes.json...');

View file

@ -1,4 +1,3 @@
import _ from "lodash";
import async from "async"; import async from "async";
import crypto from "crypto"; import crypto from "crypto";
import oldFs, {promises as fs} from "graceful-fs"; import oldFs, {promises as fs} from "graceful-fs";
@ -18,7 +17,12 @@ import {
EmailAddress, EmailAddress,
FastdKey, FastdKey,
Hostname, Hostname,
isFastdKey,
isHostname,
isMAC,
isMonitoringToken,
isStoredNode, isStoredNode,
isToken,
MAC, MAC,
MailType, MailType,
MonitoringState, MonitoringState,
@ -29,6 +33,7 @@ import {
StoredNode, StoredNode,
Token, Token,
toUnixTimestampSeconds, toUnixTimestampSeconds,
TypeGuard,
unhandledEnumField, unhandledEnumField,
UnixTimestampMilliseconds, UnixTimestampMilliseconds,
UnixTimestampSeconds UnixTimestampSeconds
@ -45,13 +50,12 @@ type NodeFilter = {
monitoringToken?: MonitoringToken, monitoringToken?: MonitoringToken,
} }
// TODO: Newtypes?
type NodeFilenameParsed = { type NodeFilenameParsed = {
hostname?: string, hostname?: Hostname,
mac?: string, mac?: MAC,
key?: string, key?: FastdKey,
token?: string, token?: Token,
monitoringToken?: string, monitoringToken?: MonitoringToken,
} }
enum LINE_PREFIX { enum LINE_PREFIX {
@ -65,7 +69,6 @@ enum LINE_PREFIX {
MONITORING_TOKEN = "# Monitoring-Token: ", MONITORING_TOKEN = "# Monitoring-Token: ",
} }
const filenameParts = ['hostname', 'mac', 'key', 'token', 'monitoringToken'];
function generateToken<Type extends string & { readonly __tag: symbol } = never>(): Type { function generateToken<Type extends string & { readonly __tag: symbol } = never>(): Type {
return crypto.randomBytes(8).toString('hex') as Type; return crypto.randomBytes(8).toString('hex') as Type;
@ -108,16 +111,20 @@ async function findFilesInPeersPath(): Promise<string[]> {
} }
function parseNodeFilename(filename: string): NodeFilenameParsed { function parseNodeFilename(filename: string): NodeFilenameParsed {
const parts = filename.split('@', filenameParts.length); const parts = filename.split('@', 5);
const parsed: { [key: string]: string | undefined } = {};
const zippedParts = _.zip<string, string>(filenameParts, parts); function get<T>(isT: TypeGuard<T>, index: number): T | undefined {
for (const part of zippedParts) { const value = index >= 0 && index < parts.length ? parts[index] : undefined;
const key = part[0]; return isT(value) ? value : undefined;
if (key) {
parsed[key] = part[1];
}
} }
return parsed;
return {
hostname: get(isHostname, 0),
mac: get(isMAC, 1),
key: get(isFastdKey, 2),
token: get(isToken, 3),
monitoringToken: get(isMonitoringToken, 4),
};
} }
function isDuplicate(filter: NodeFilter, token?: Token): boolean { function isDuplicate(filter: NodeFilter, token?: Token): boolean {
@ -446,7 +453,7 @@ export async function updateNode(token: Token, node: CreateOrUpdateNode): Promis
// monitoring just has been enabled // monitoring just has been enabled
monitoringState = MonitoringState.PENDING; monitoringState = MonitoringState.PENDING;
monitoringToken = generateToken<MonitoringToken>(); monitoringToken = generateToken<MonitoringToken>();
break; break;
case MonitoringState.PENDING: case MonitoringState.PENDING:
case MonitoringState.ACTIVE: case MonitoringState.ACTIVE:
@ -460,7 +467,7 @@ export async function updateNode(token: Token, node: CreateOrUpdateNode): Promis
monitoringState = currentNode.monitoringState; monitoringState = currentNode.monitoringState;
monitoringToken = nodeSecrets.monitoringToken || generateToken<MonitoringToken>(); monitoringToken = nodeSecrets.monitoringToken || generateToken<MonitoringToken>();
} }
break; break;
default: default:
unhandledEnumField(currentNode.monitoringState); unhandledEnumField(currentNode.monitoringState);