Files
directus/api/src/extensions.ts
2020-10-21 18:28:16 +02:00

130 lines
3.4 KiB
TypeScript

import listFolders from './utils/list-folders';
import path from 'path';
import env from './env';
import { ServiceUnavailableException } from './exceptions';
import express, { Router } from 'express';
import emitter from './emitter';
import logger from './logger';
import { HookRegisterFunction, EndpointRegisterFunction } from './types';
import { ensureDir } from 'fs-extra';
import * as exceptions from './exceptions';
import * as services from './services';
import database from './database';
export async function ensureFoldersExist() {
const folders = ['endpoints', 'hooks', 'interfaces', 'modules', 'layouts', 'displays'];
for (const folder of folders) {
const folderPath = path.resolve(env.EXTENSIONS_PATH, folder);
try {
await ensureDir(folderPath);
} catch (err) {
logger.warn(err);
}
}
}
export async function listExtensions(type: string) {
const extensionsPath = env.EXTENSIONS_PATH as string;
const location = path.join(extensionsPath, type);
try {
return await listFolders(location);
} catch (err) {
if (err.code === 'ENOENT') {
throw new ServiceUnavailableException(
`Extension folder "extensions/${type}" couldn't be opened`,
{
service: 'extensions',
}
);
}
throw err;
}
}
export async function registerExtensions(router: Router) {
await ensureFoldersExist();
let hooks: string[] = [];
let endpoints: string[] = [];
try {
hooks = await listExtensions('hooks');
registerHooks(hooks);
} catch (err) {
logger.warn(err);
}
try {
endpoints = await listExtensions('endpoints');
registerEndpoints(endpoints, router);
} catch (err) {
logger.warn(err);
}
}
function registerHooks(hooks: string[]) {
const extensionsPath = env.EXTENSIONS_PATH as string;
for (const hook of hooks) {
try {
registerHook(hook);
} catch (error) {
logger.warn(`Couldn't register hook "${hook}"`);
logger.warn(error);
}
}
function registerHook(hook: string) {
const hookPath = path.resolve(extensionsPath, 'hooks', hook, 'index.js');
const hookInstance:
| HookRegisterFunction
| { default?: HookRegisterFunction } = require(hookPath);
let register: HookRegisterFunction = hookInstance as HookRegisterFunction;
if (typeof hookInstance !== 'function') {
if (hookInstance.default) {
register = hookInstance.default;
}
}
let events = register({ services, exceptions, env, database });
for (const [event, handler] of Object.entries(events)) {
emitter.on(event, handler);
}
}
}
function registerEndpoints(endpoints: string[], router: Router) {
const extensionsPath = env.EXTENSIONS_PATH as string;
for (const endpoint of endpoints) {
try {
registerEndpoint(endpoint);
} catch (error) {
logger.warn(`Couldn't register endpoint "${endpoint}"`);
logger.warn(error);
}
}
function registerEndpoint(endpoint: string) {
const endpointPath = path.resolve(extensionsPath, 'endpoints', endpoint, 'index.js');
const endpointInstance:
| EndpointRegisterFunction
| { default?: EndpointRegisterFunction } = require(endpointPath);
let register: EndpointRegisterFunction = endpointInstance as EndpointRegisterFunction;
if (typeof endpointInstance !== 'function') {
if (endpointInstance.default) {
register = endpointInstance.default;
}
}
const scopedRouter = express.Router();
router.use(`/${endpoint}/`, scopedRouter);
register(scopedRouter, { services, exceptions, env, database });
}
}