Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 5 additions & 13 deletions src/adapter/deconz/adapter/deconzAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import {existsSync, readFileSync} from "node:fs";
import {dirname} from "node:path";
import type * as Models from "../../../models";
import type {Backup, UnifiedBackupStorage} from "../../../models";
import type {Backup} from "../../../models";
import {BackupUtils, Waitress} from "../../../utils";
import {logger} from "../../../utils/logger";
import * as ZSpec from "../../../zspec";
Expand All @@ -15,6 +15,7 @@ import type * as ZdoTypes from "../../../zspec/zdo/definition/tstypes";
import Adapter from "../../adapter";
import type * as Events from "../../events";
import type {AdapterOptions, CoordinatorVersion, NetworkOptions, NetworkParameters, SerialPortOptions, StartResult} from "../../tstype";
import {readBackup} from "../../utils";
import PARAM, {
ApsAddressMode,
type ApsDataRequest,
Expand Down Expand Up @@ -558,19 +559,10 @@ export class DeconzAdapter extends Adapter {
* Loads currently stored backup and returns it in internal backup model.
*/
private getStoredBackup(): Backup | undefined {
if (!existsSync(this.backupPath)) {
return undefined;
}

let data: UnifiedBackupStorage;

try {
data = JSON.parse(readFileSync(this.backupPath).toString());
} catch (error) {
throw new Error(`[BACKUP] Coordinator backup is corrupted. (${(error as Error).stack})`);
}
const data = readBackup(this.backupPath);
if (!data) return undefined;

if (data.metadata?.format === "zigpy/open-coordinator-backup" && data.metadata?.version) {
if ("metadata" in data && data.metadata?.format === "zigpy/open-coordinator-backup" && data.metadata?.version) {
if (data.metadata?.version !== 1) {
throw new Error(`[BACKUP] Unsupported open coordinator backup version (version=${data.metadata?.version}).`);
}
Expand Down
6 changes: 3 additions & 3 deletions src/adapter/deconz/driver/driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import {Buffalo} from "../../../buffalo";
import type {Backup} from "../../../models";
import {logger} from "../../../utils/logger";
import {SerialPort} from "../../serialPort";
import SocketPortUtils from "../../socketPortUtils";
import type {NetworkOptions, SerialPortOptions} from "../../tstype";
import {isTcpPath, parseTcpPath} from "../../utils";
import PARAM, {
ApsAddressMode,
type ApsDataRequest,
Expand Down Expand Up @@ -362,7 +362,7 @@ class Driver extends events.EventEmitter {
}

let prom: Promise<void> | undefined;
if (SocketPortUtils.isTcpPath(this.serialPortOptions.path)) {
if (isTcpPath(this.serialPortOptions.path)) {
prom = this.openSocketPort();
} else if (baudrate) {
prom = this.openSerialPort(baudrate);
Expand Down Expand Up @@ -893,7 +893,7 @@ class Driver extends events.EventEmitter {
throw new Error("No serial port TCP path specified");
}

const info = SocketPortUtils.parseTcpPath(this.serialPortOptions.path);
const info = parseTcpPath(this.serialPortOptions.path);
logger.debug(`Opening TCP socket with ${info.host}:${info.port}`, NS);
this.socketPort = new net.Socket();
this.socketPort.setNoDelay(true);
Expand Down
20 changes: 6 additions & 14 deletions src/adapter/ember/adapter/emberAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {randomBytes} from "node:crypto";
import {existsSync, readFileSync, renameSync} from "node:fs";
import {readFileSync, renameSync} from "node:fs";
import path from "node:path";

import equals from "fast-deep-equal/es6";
import type {Backup, UnifiedBackupStorage} from "../../../models";
import type {Backup} from "../../../models";
import {BackupUtils, Queue, wait} from "../../../utils";
import {logger} from "../../../utils/logger";
import * as ZSpec from "../../../zspec";
Expand All @@ -14,6 +14,7 @@ import type * as ZdoTypes from "../../../zspec/zdo/definition/tstypes";
import {Adapter, type TsType} from "../..";
import {WORKAROUND_JOIN_MANUF_IEEE_PREFIX_TO_CODE} from "../../const";
import type {DeviceJoinedPayload, DeviceLeavePayload, ZclPayload} from "../../events";
import {readBackup} from "../../utils";
import {
EMBER_HIGH_RAM_CONCENTRATOR,
EMBER_LOW_RAM_CONCENTRATOR,
Expand Down Expand Up @@ -1141,19 +1142,10 @@ export class EmberAdapter extends Adapter {
* Loads currently stored backup and returns it in internal backup model.
*/
private getStoredBackup(): Backup | undefined {
if (!existsSync(this.backupPath)) {
return undefined;
}

let data: UnifiedBackupStorage;

try {
data = JSON.parse(readFileSync(this.backupPath).toString());
} catch (error) {
throw new Error(`[BACKUP] Coordinator backup is corrupted. (${(error as Error).stack})`);
}
const data = readBackup(this.backupPath);
if (!data) return undefined;

if (data.metadata?.format === "zigpy/open-coordinator-backup" && data.metadata?.version) {
if ("metadata" in data && data.metadata?.format === "zigpy/open-coordinator-backup" && data.metadata?.version) {
if (data.metadata?.version !== 1) {
throw new Error(`[BACKUP] Unsupported open coordinator backup version (version=${data.metadata?.version}).`);
}
Expand Down
8 changes: 4 additions & 4 deletions src/adapter/ember/uart/ash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {Socket} from "node:net";
import {wait} from "../../../utils";
import {logger} from "../../../utils/logger";
import {SerialPort} from "../../serialPort";
import SocketPortUtils from "../../socketPortUtils";
import type {SerialPortOptions} from "../../tstype";
import {isTcpPath, parseTcpPath} from "../../utils";
import {EzspStatus} from "../enums";
import {halCommonCrc16, inc8, mod8, withinRange} from "../utils/math";
import {
Expand Down Expand Up @@ -410,7 +410,7 @@ export class UartAsh extends EventEmitter<UartAshEventMap> {
}

// biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
if (SocketPortUtils.isTcpPath(this.portOptions.path!)) {
if (isTcpPath(this.portOptions.path!)) {
return this.socketPort ? !this.socketPort.closed : false;
}

Expand Down Expand Up @@ -463,7 +463,7 @@ export class UartAsh extends EventEmitter<UartAshEventMap> {
await this.closePort(); // will do nothing if nothing's open

// biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
if (!SocketPortUtils.isTcpPath(this.portOptions.path!)) {
if (!isTcpPath(this.portOptions.path!)) {
const serialOpts = {
// biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
path: this.portOptions.path!,
Expand Down Expand Up @@ -509,7 +509,7 @@ export class UartAsh extends EventEmitter<UartAshEventMap> {
}
} else {
// biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
const info = SocketPortUtils.parseTcpPath(this.portOptions.path!);
const info = parseTcpPath(this.portOptions.path!);
logger.debug(`Opening TCP socket with ${info.host}:${info.port}`, NS);

this.socketPort = new Socket();
Expand Down
19 changes: 5 additions & 14 deletions src/adapter/ezsp/adapter/backup.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
/* v8 ignore start */

import * as fs from "node:fs";

import type * as Models from "../../../models";
import {BackupUtils} from "../../../utils";
import {logger} from "../../../utils/logger";
import {uint32MaskToChannels} from "../../../zspec/utils";
import {readBackup} from "../../utils";
import type {Driver} from "../driver";
import {
type EmberKeyData,
Expand Down Expand Up @@ -83,18 +82,10 @@ export class EZSPAdapterBackup {
* Loads currently stored backup and returns it in internal backup model.
*/
public getStoredBackup(): Models.Backup | undefined {
try {
fs.accessSync(this.defaultPath);
} catch {
return undefined;
}
let data: Models.UnifiedBackupStorage;
try {
data = JSON.parse(fs.readFileSync(this.defaultPath).toString());
} catch (error) {
throw new Error(`Coordinator backup is corrupted (${(error as Error).stack})`);
}
if (data.metadata?.format === "zigpy/open-coordinator-backup" && data.metadata?.version) {
const data = readBackup(this.defaultPath);
if (!data) return undefined;

if ("metadata" in data && data.metadata?.format === "zigpy/open-coordinator-backup" && data.metadata?.version) {
if (data.metadata?.version !== 1) {
throw new Error(`Unsupported open coordinator backup version (version=${data.metadata?.version})`);
}
Expand Down
6 changes: 3 additions & 3 deletions src/adapter/ezsp/driver/uart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import net from "node:net";
import {Queue, Waitress, wait} from "../../../utils";
import {logger} from "../../../utils/logger";
import {SerialPort} from "../../serialPort";
import SocketPortUtils from "../../socketPortUtils";
import type {SerialPortOptions} from "../../tstype";
import {isTcpPath, parseTcpPath} from "../../utils";
import {FrameType, Frame as NpiFrame} from "./frame";
import {Parser} from "./parser";
import {Writer} from "./writer";
Expand Down Expand Up @@ -58,7 +58,7 @@ export class SerialDriver extends EventEmitter {

async connect(options: SerialPortOptions): Promise<void> {
// biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
if (SocketPortUtils.isTcpPath(options.path!)) {
if (isTcpPath(options.path!)) {
// biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
await this.openSocketPort(options.path!);
} else {
Expand Down Expand Up @@ -118,7 +118,7 @@ export class SerialDriver extends EventEmitter {
}

private async openSocketPort(path: string): Promise<void> {
const info = SocketPortUtils.parseTcpPath(path);
const info = parseTcpPath(path);
logger.debug(`Opening TCP socket with ${info.host}:${info.port}`, NS);

this.socketPort = new net.Socket();
Expand Down
16 changes: 0 additions & 16 deletions src/adapter/socketPortUtils.ts

This file was deleted.

33 changes: 33 additions & 0 deletions src/adapter/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {existsSync, readFileSync} from "node:fs";
import type * as Models from "../models";

export function isTcpPath(path: string): boolean {
// tcp path must be:
// tcp://<host>:<port>
const regex = /^(?:tcp:\/\/)[\w.-]+[:][\d]+$/gm;
return regex.test(path);
}

export function parseTcpPath(path: string): {host: string; port: number} {
// built-in extra validation
const info = new URL(path);

return {
host: info.hostname,
port: Number(info.port),
};
}

export function readBackup(path: string): Models.UnifiedBackupStorage | Models.LegacyBackupStorage | undefined {
if (!existsSync(path)) {
return undefined;
}

try {
return JSON.parse(readFileSync(path).toString());
} catch (error) {
throw new Error(
`[BACKUP] Coordinator backup is corrupted. This can happen due to filesystem corruption. To re-create the backup, delete '${path}' and start again. (${(error as Error).stack})`,
);
}
}
20 changes: 5 additions & 15 deletions src/adapter/z-stack/adapter/adapter-backup.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import assert from "node:assert";
import * as fs from "node:fs";

import type * as Models from "../../../models";
import {BackupUtils} from "../../../utils";
import {logger} from "../../../utils/logger";
import {NULL_NODE_ID, Utils as ZSpecUtils} from "../../../zspec";
import {readBackup} from "../../utils";
import {NvItemsIds, NvSystemIds} from "../constants/common";
import * as Structs from "../structs";
import {AddressManagerUser, SecurityManagerAuthenticationOption} from "../structs";
Expand Down Expand Up @@ -34,27 +33,18 @@ export class AdapterBackup {
* Loads currently stored backup and returns it in internal backup model.
*/
public getStoredBackup(): Models.Backup | undefined {
try {
fs.accessSync(this.defaultPath);
} catch {
return undefined;
}
let data: Models.UnifiedBackupStorage | Models.LegacyBackupStorage;
try {
data = JSON.parse(fs.readFileSync(this.defaultPath).toString());
} catch (error) {
throw new Error(`Coordinator backup is corrupted (${error})`);
}
const data = readBackup(this.defaultPath);
if (!data) return undefined;

if ("adapterType" in data) {
return BackupUtils.fromLegacyBackup(data as Models.LegacyBackupStorage);
return BackupUtils.fromLegacyBackup(data);
}

if (data.metadata?.format === "zigpy/open-coordinator-backup" && data.metadata?.version) {
if (data.metadata?.version !== 1) {
throw new Error(`Unsupported open coordinator backup version (version=${data.metadata?.version})`);
}
return BackupUtils.fromUnifiedBackup(data as Models.UnifiedBackupStorage);
return BackupUtils.fromUnifiedBackup(data);
}

throw new Error("Unknown backup format");
Expand Down
6 changes: 3 additions & 3 deletions src/adapter/z-stack/znp/znp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {Queue, Waitress, wait} from "../../../utils";
import {logger} from "../../../utils/logger";
import {ClusterId as ZdoClusterId} from "../../../zspec/zdo";
import {SerialPort} from "../../serialPort";
import SocketPortUtils from "../../socketPortUtils";
import {isTcpPath, parseTcpPath} from "../../utils";
import * as Constants from "../constants";
import {Frame as UnpiFrame, Parser as UnpiParser, Writer as UnpiWriter} from "../unpi";
import {Subsystem, Type} from "../unpi/constants";
Expand Down Expand Up @@ -91,7 +91,7 @@ export class Znp extends events.EventEmitter {
}

public async open(): Promise<void> {
return SocketPortUtils.isTcpPath(this.path) ? await this.openSocketPort() : await this.openSerialPort();
return isTcpPath(this.path) ? await this.openSocketPort() : await this.openSerialPort();
}

private async openSerialPort(): Promise<void> {
Expand Down Expand Up @@ -126,7 +126,7 @@ export class Znp extends events.EventEmitter {
}

private async openSocketPort(): Promise<void> {
const info = SocketPortUtils.parseTcpPath(this.path);
const info = parseTcpPath(this.path);
logger.info(`Opening TCP socket with ${info.host}:${info.port}`, NS);

this.socketPort = new Socket();
Expand Down
8 changes: 4 additions & 4 deletions src/adapter/zboss/uart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {Socket} from "node:net";
import {Queue, Waitress, wait} from "../../utils";
import {logger} from "../../utils/logger";
import {SerialPort} from "../serialPort";
import SocketPortUtils from "../socketPortUtils";
import type {SerialPortOptions} from "../tstype";
import {isTcpPath, parseTcpPath} from "../utils";
import {SIGNATURE, ZBOSS_FLAG_FIRST_FRAGMENT, ZBOSS_FLAG_LAST_FRAGMENT, ZBOSS_NCP_API_HL} from "./consts";
import {readZBOSSFrame, writeZBOSSFrame, type ZBOSSFrame} from "./frame";
import {ZBOSSReader} from "./reader";
Expand Down Expand Up @@ -68,7 +68,7 @@ export class ZBOSSUart extends EventEmitter {
return false;
}
// biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
if (SocketPortUtils.isTcpPath(this.portOptions.path!)) {
if (isTcpPath(this.portOptions.path!)) {
return this.socketPort && !this.socketPort.closed;
}

Expand Down Expand Up @@ -106,7 +106,7 @@ export class ZBOSSUart extends EventEmitter {
await this.closePort();

// biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
if (!SocketPortUtils.isTcpPath(this.portOptions.path!)) {
if (!isTcpPath(this.portOptions.path!)) {
const serialOpts = {
// biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
path: this.portOptions.path!,
Expand Down Expand Up @@ -141,7 +141,7 @@ export class ZBOSSUart extends EventEmitter {
}
} else {
// biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
const info = SocketPortUtils.parseTcpPath(this.portOptions.path!);
const info = parseTcpPath(this.portOptions.path!);
logger.debug(`Opening TCP socket with ${info.host}:${info.port}`, NS);

this.socketPort = new Socket();
Expand Down
6 changes: 3 additions & 3 deletions src/adapter/zigate/driver/zigate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import * as ZSpec from "../../../zspec";
import * as Zdo from "../../../zspec/zdo";
import type {EndDeviceAnnounce, GenericZdoResponse, ResponseMap as ZdoResponseMap} from "../../../zspec/zdo/definition/tstypes";
import {SerialPort} from "../../serialPort";
import SocketPortUtils from "../../socketPortUtils";
import type {SerialPortOptions} from "../../tstype";
import {isTcpPath, parseTcpPath} from "../../utils";
import {equal, type ZiGateResponseMatcher, type ZiGateResponseMatcherRule} from "./commandType";
import {Status, ZDO_REQ_CLUSTER_ID_TO_ZIGATE_COMMAND_ID, ZiGateCommandCode, ZiGateMessageCode, type ZiGateObjectPayload} from "./constants";
import ZiGateFrame from "./frame";
Expand Down Expand Up @@ -195,7 +195,7 @@ export default class ZiGate extends EventEmitter<ZiGateEventMap> {
}

public open(): Promise<void> {
return SocketPortUtils.isTcpPath(this.path) ? this.openSocketPort() : this.openSerialPort();
return isTcpPath(this.path) ? this.openSocketPort() : this.openSerialPort();
}

public async close(): Promise<void> {
Expand Down Expand Up @@ -256,7 +256,7 @@ export default class ZiGate extends EventEmitter<ZiGateEventMap> {
}

private async openSocketPort(): Promise<void> {
const info = SocketPortUtils.parseTcpPath(this.path);
const info = parseTcpPath(this.path);
logger.debug(`Opening TCP socket with ${info.host}:${info.port}`, NS);

this.socketPort = new net.Socket();
Expand Down
Loading