"use strict"; const Promise = require("bluebird"); const dlayerSource = require("../../packages/dlayer-source"); const treecutter = require("../../packages/treecutter"); const upperSnakeCase = require("../../packages/upper-snake-case"); const types = require("./"); module.exports = function Drive ({ path }) { return dlayerSource.withSources({ path: path, blockDevice: async function(_, { $getProperty }) { if (await $getProperty(this, "interface") === "nvme") { return null; } else { return types.BlockDevice({ path: path }); } }, allBlockDevices: async function(_, { $getProperty, sources }) { return Promise.try(async () => { if (await $getProperty(this, "interface") === "nvme") { return Promise.try(() => { return sources.nvmeListNamespaces.load(path); }).map((namespaceID) => { return `${path}n${namespaceID}`; }); } else { return [ path ]; } }).then((rootPaths) => { let queries = rootPaths.map((path) => ({ path: path })); return sources.lsblk.loadMany(queries); }).map((blockDeviceTree) => { return treecutter.map(blockDeviceTree, (device) => types.BlockDevice(device)); }).then((resultArray) => { // Treecutter always returns an array, regardless of whether the input was an array or not, so we need to flatten it since we will only ever have a single root entry per rootPath query here return resultArray.flat(); }); }, $sources: { // lsblk: { // [dlayerSource.ID]: { path }, // }, smartctlScan: { [dlayerSource.ID]: path, interface: "interface" }, smartctlInfo: { [dlayerSource.ID]: path, model: "model", modelFamily: "modelFamily", smartAvailable: "smartAvailable", smartEnabled: "smartEnabled", serialNumber: "serialNumber", wwn: "wwn", firmwareVersion: "firmwareVersion", size: "size", rpm: "rpm", logicalSectorSize: (device) => device.sectorSizes.logical, physicalSectorSize: (device) => device.sectorSizes.physical, formFactor: "formFactor", ataVersion: "ataVersion", sataVersion: "sataVersion" }, smartctlAttributes: { [dlayerSource.ID]: path, smartAttributes: (attributes) => { return attributes.map((attribute) => { return { ... attribute, type: upperSnakeCase(attribute.type), updatedWhen: upperSnakeCase(attribute.updatedWhen) }; }); }, smartHealth: (attributes) => { let failed = attributes.filter((item) => { return (item.failingNow === true || item.failedBefore === true); }); let deteriorating = attributes.filter((item) => { return (item.type === "preFail" && item.worstValueSeen < 100); }); if (failed.length > 0) { return "FAILING"; } else if (deteriorating.length > 0) { return "DETERIORATING"; } else { return "HEALTHY"; } } } } }); };