mirror of
https://github.com/unraid/api.git
synced 2026-01-15 05:00:16 -06:00
192 lines
4.6 KiB
TypeScript
192 lines
4.6 KiB
TypeScript
/*!
|
|
* Copyright 2019-2020 Lime Technology Inc. All rights reserved.
|
|
* Written by: Alexis Tyler
|
|
*/
|
|
|
|
import path from 'path';
|
|
import glob from 'glob';
|
|
import camelCase from 'camelcase';
|
|
import globby from 'globby';
|
|
import pIteration from 'p-iteration';
|
|
import clearModule from 'clear-module';
|
|
import { coreLogger } from './log';
|
|
import { paths } from './paths';
|
|
import { subscribeToNchanEndpoint } from './utils';
|
|
import { config } from './config';
|
|
import { pluginManager } from './plugin-manager';
|
|
import * as watchers from './watchers';
|
|
|
|
// Have plugins loaded at least once
|
|
let pluginsLoaded = false;
|
|
|
|
// Magic values
|
|
const ONE_SECOND = 1000;
|
|
const TEN_SECONDS = 10 * ONE_SECOND;
|
|
|
|
/**
|
|
* Decorated loading logger.
|
|
* @param namespace
|
|
* @param all
|
|
* @param filePath
|
|
*/
|
|
const loadingLogger = (namespace: string): void => {
|
|
coreLogger.debug('Loading %s', namespace);
|
|
};
|
|
|
|
/**
|
|
* Register state paths.
|
|
*/
|
|
const loadStatePaths = async (): Promise<void> => {
|
|
const statesCwd = paths.get('states')!;
|
|
const cwd = path.join(__dirname, 'states');
|
|
|
|
loadingLogger('state paths');
|
|
|
|
const states = glob.sync('*.js', { cwd }).map(state => state.replace('.js', ''));
|
|
states.forEach(state => {
|
|
const name = `state:${camelCase(state, { pascalCase: true })}`;
|
|
const filePath = `${path.join(statesCwd, state)}.ini`;
|
|
|
|
// Don't override already set paths
|
|
// @ts-expect-error
|
|
if (!paths.has(name)) {
|
|
// ['state:Users', '/usr/local/emhttp/state/users.ini']
|
|
// @ts-expect-error
|
|
paths.set(name, filePath);
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Register all plugins with PluginManager.
|
|
*/
|
|
const loadPlugins = async (): Promise<void> => {
|
|
// Bail in safe mode
|
|
if (config.get('safe-mode')) {
|
|
coreLogger.debug('No plugins have been loaded as you\'re in SAFE MODE');
|
|
return;
|
|
}
|
|
|
|
// Bail if there isn't a plugins directory
|
|
if (!paths.get('plugins')) {
|
|
coreLogger.debug('No plugins have been loaded as there was no plugins directory found.');
|
|
return;
|
|
}
|
|
|
|
const pluginsCwd = paths.get('plugins')!;
|
|
const packages = globby
|
|
.sync(['**/package.json', '!**/node_modules/**'], { cwd: pluginsCwd })
|
|
// Remove all files
|
|
.filter(packageName => packageName.includes('/'));
|
|
const plugins = packages.map(plugin => plugin.replace('/package.json', ''));
|
|
|
|
loadingLogger('plugins');
|
|
|
|
// Reset caches so plugins can load from fresh state
|
|
if (pluginsLoaded) {
|
|
// Reset plugin manager
|
|
pluginManager.reset();
|
|
|
|
// Reset require cache
|
|
// Without this plugin files wouldn't update until the server restarts
|
|
await pIteration.forEach(plugins, async pluginName => {
|
|
const cwd = path.join(pluginsCwd, pluginName);
|
|
const pluginFiles = globby.sync(['**/*', '!**/node_modules/**'], { cwd });
|
|
await pIteration.forEach(pluginFiles, pluginFile => {
|
|
const filePath = path.join(pluginsCwd, pluginFile);
|
|
coreLogger.debug('Clearing plugin file from require cache %s', filePath);
|
|
clearModule(filePath);
|
|
});
|
|
});
|
|
} else {
|
|
// Update flag
|
|
pluginsLoaded = true;
|
|
}
|
|
|
|
// Initialize all plugins with plugin manager
|
|
await pIteration.forEach(plugins, async pluginName => pluginManager.init(pluginName));
|
|
};
|
|
|
|
/**
|
|
* Start all watchers.
|
|
*/
|
|
const loadWatchers = async (): Promise<void> => {
|
|
if (config.get('safe-mode')) {
|
|
coreLogger.debug('Skipping loading watchers');
|
|
return;
|
|
}
|
|
|
|
const watchersCwd = path.join(__dirname, 'watchers');
|
|
loadingLogger('watchers');
|
|
|
|
// Start each watcher
|
|
Object.values(watchers).forEach(watcher => {
|
|
watcher().start();
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Add api keys for users, etc.
|
|
*
|
|
* @name core.loadApiKeys
|
|
* @async
|
|
* @private
|
|
*/
|
|
const loadApiKeys = async (): Promise<void> => {
|
|
// @TODO: For each key in a json file load them
|
|
};
|
|
|
|
/**
|
|
* Connect to nchan endpoints.
|
|
*
|
|
* @param endpoints
|
|
*/
|
|
const connectToNchanEndpoints = async (endpoints: string[]): Promise<void> => {
|
|
coreLogger.debug('Connected to nchan, setting-up endpoints.');
|
|
const connections = endpoints.map(async endpoint => subscribeToNchanEndpoint(endpoint));
|
|
await Promise.all(connections);
|
|
};
|
|
|
|
/**
|
|
* Start nchan subscriptions
|
|
*
|
|
* @name core.loadNchan
|
|
* @async
|
|
* @private
|
|
*/
|
|
const loadNchan = async (): Promise<void> => {
|
|
const endpoints = ['devs', 'disks', 'sec', 'sec_nfs', 'shares', 'users', 'var'];
|
|
|
|
coreLogger.debug('Trying to connect to nchan');
|
|
|
|
// Connect to each known endpoint
|
|
await connectToNchanEndpoints(endpoints);
|
|
};
|
|
|
|
/**
|
|
* Core loaders.
|
|
*/
|
|
const loaders = {
|
|
statePaths: loadStatePaths,
|
|
plugins: loadPlugins,
|
|
watchers: loadWatchers
|
|
};
|
|
|
|
/**
|
|
* Main load function
|
|
*
|
|
* @name core.load
|
|
*/
|
|
const load = async (): Promise<void> => {
|
|
await loadStatePaths();
|
|
await loadPlugins();
|
|
await loadWatchers();
|
|
await loadApiKeys();
|
|
};
|
|
|
|
export const core = {
|
|
loaders,
|
|
load,
|
|
loadNchan
|
|
};
|