"use strict"; const Promise = require("bluebird"); const memoizee = require("memoizee"); const DataLoader = require("dataloader"); const mapObj = require("map-obj"); const lvm = require("../../packages/exec-lvm"); const All = require("../../packages/graphql-interface/symbols/all"); const nvmeCLI = require("../../packages/exec-nvme-cli"); const smartctl = require("../../packages/exec-smartctl"); const dlayerWrap = require("../../packages/dlayer-wrap"); // This generates a (memoized) source function for commands that always produce an entire list, that needs to be filtered for the desired item(s) function makeListCommand({ command, selectResult, selectID }) { let commandOnce = memoizee(command); return function (ids) { return Promise.try(() => { return commandOnce(); }).then((result) => { if (selectResult != null) { return selectResult(result); } else { return result; } }).then((items) => { return ids.map((id) => { if (id === All) { return items; } else { return items.find((item) => selectID(item) === id); } }); }); }; } function makeSingleCommand({ command, selectResult }) { return function (ids) { return Promise.map(ids, (id) => { if (id === All) { // FIXME: Have some sort of mechanism for making this possible? throw new Error(`This data source does not support fetching all entries`); } else { return command(id); } }).map((result) => { if (selectResult != null) { return selectResult(result); } else { return result; } }); }; } module.exports = function createSources() { let sources = { lvmLogicalVolumes: makeListCommand({ command: lvm.getLogicalVolumes, selectResult: (result) => result.volumes, selectID: (volume) => volume.path }), lvmPhysicalVolumes: makeListCommand({ command: lvm.getPhysicalVolumes, selectResult: (result) => result.volumes, selectID: (device) => device.path }), lvmVolumeGroups: makeListCommand({ command: lvm.getVolumeGroups, selectResult: (result) => result.groups, selectID: (group) => group.name }), nvmeIdentifyController: makeSingleCommand({ command: (path) => nvmeCLI.identifyController({ devicePath: path }) }), nvmeListNamespaces: makeSingleCommand({ command: (path) => nvmeCLI.listNamespaces({ devicePath: path }) }), smartctlScan: makeListCommand({ command: smartctl.scan, selectID: (device) => device.path }), smartctlInfo: makeSingleCommand({ command: (path) => dlayerWrap(() => smartctl.info({ devicePath: path }), { allowedErrors: [ smartctl.InfoError ] }) }), smartctlAttributes: makeSingleCommand({ command: (path) => dlayerWrap(() => smartctl.attributes({ devicePath: path }), { allowedErrors: [ smartctl.AttributesError ] }) }), }; let factoryModules = { lsblk: require("./lsblk")(), findmnt: require("./findmnt")() }; return mapObj({ ... factoryModules, ... sources }, (name, factory) => { return [ name, new DataLoader(factory) ]; }); };