mirror of
https://github.com/unraid/api.git
synced 2026-05-01 20:54:27 -05:00
91 lines
2.5 KiB
TypeScript
91 lines
2.5 KiB
TypeScript
/*!
|
|
* Copyright 2019-2020 Lime Technology Inc. All rights reserved.
|
|
* Written by: Alexis Tyler
|
|
*/
|
|
|
|
import execa from 'execa';
|
|
import { Systeminformation, blockDevices, diskLayout } from 'systeminformation';
|
|
import { map as asyncMap } from 'p-iteration';
|
|
import { CoreContext, CoreResult } from '../types';
|
|
import { uppercaseFirstChar, ensurePermission } from '../utils';
|
|
|
|
interface Partition {
|
|
name: string;
|
|
fsType: string;
|
|
size: number;
|
|
}
|
|
|
|
interface Disk extends Systeminformation.DiskLayoutData {
|
|
smartStatus: string;
|
|
interfaceType: string;
|
|
temperature: number;
|
|
partitions: Partition[];
|
|
}
|
|
|
|
const getTemperature = async (disk: Systeminformation.DiskLayoutData): Promise<number> => {
|
|
const stdout = await execa('smartctl', ['-A', disk.device]).then(({ stdout }) => stdout).catch(() => '');
|
|
const lines = stdout.split('\n');
|
|
const header = lines.find(line => line.startsWith('ID#'))!;
|
|
const fields = lines.splice(lines.indexOf(header) + 1, lines.length);
|
|
const field = fields.find(line => {
|
|
return line.includes('Temperature_Celsius') || line.includes('Airflow_Temperature_Cel');
|
|
});
|
|
|
|
if (!field) {
|
|
return -1;
|
|
}
|
|
|
|
if (field.includes('Min/Max')) {
|
|
return Number.parseInt(field.split(' - ')[1].trim().split(' ')[0], 10);
|
|
}
|
|
|
|
const line = field.split(' ');
|
|
return Number.parseInt(line[line.length - 1], 10);
|
|
};
|
|
|
|
const parseDisk = async (disk: Systeminformation.DiskLayoutData, partitionsToParse: Systeminformation.BlockDevicesData[]): Promise<Disk> => {
|
|
const partitions = partitionsToParse
|
|
// Only get partitions from this disk
|
|
.filter(partition => partition.name.startsWith(disk.device.split('/dev/')[1]))
|
|
// Remove unneeded fields
|
|
.map(({ name, fstype, size }) => ({
|
|
name,
|
|
fsType: fstype,
|
|
size
|
|
}));
|
|
|
|
return {
|
|
...disk,
|
|
smartStatus: uppercaseFirstChar(disk.smartStatus.toLowerCase()),
|
|
interfaceType: disk.interfaceType || 'UNKNOWN',
|
|
temperature: await getTemperature(disk),
|
|
partitions
|
|
};
|
|
};
|
|
|
|
interface Result extends CoreResult {
|
|
json: Disk[];
|
|
}
|
|
|
|
/**
|
|
* Get all disks.
|
|
*/
|
|
export const getDisks = async (context: CoreContext): Promise<Result> => {
|
|
const { user } = context;
|
|
|
|
// Check permissions
|
|
ensurePermission(user, {
|
|
resource: 'disk',
|
|
action: 'read',
|
|
possession: 'any'
|
|
});
|
|
|
|
const partitions = await blockDevices().then(devices => devices.filter(device => device.type === 'part'));
|
|
const disks = await asyncMap(await diskLayout(), async disk => parseDisk(disk, partitions));
|
|
|
|
return {
|
|
text: `Disks: ${JSON.stringify(disks, null, 2)}`,
|
|
json: disks
|
|
};
|
|
};
|