config-loader.ts 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. import type { IConfigLoader, RawConfigData } from '@growi/core/dist/interfaces';
  2. import { toBoolean } from '@growi/core/dist/utils/env-utils';
  3. import loggerFactory from '~/utils/logger';
  4. import type { ConfigKey, ConfigValues } from './config-definition';
  5. import { CONFIG_DEFINITIONS } from './config-definition';
  6. const logger = loggerFactory('growi:service:ConfigLoader');
  7. export class ConfigLoader implements IConfigLoader<ConfigKey, ConfigValues> {
  8. async loadFromEnv(): Promise<RawConfigData<ConfigKey, ConfigValues>> {
  9. const envConfig = {} as RawConfigData<ConfigKey, ConfigValues>;
  10. for (const [key, metadata] of Object.entries(CONFIG_DEFINITIONS)) {
  11. let configValue = metadata.defaultValue;
  12. if (metadata.envVarName != null) {
  13. const envVarValue = process.env[metadata.envVarName];
  14. if (envVarValue != null) {
  15. configValue = this.parseEnvValue(envVarValue, typeof metadata.defaultValue) as ConfigValues[ConfigKey];
  16. }
  17. }
  18. envConfig[key as ConfigKey] = {
  19. definition: metadata,
  20. value: configValue,
  21. };
  22. }
  23. logger.debug('loadFromEnv', envConfig);
  24. return envConfig;
  25. }
  26. async loadFromDB(): Promise<RawConfigData<ConfigKey, ConfigValues>> {
  27. const dbConfig = {} as RawConfigData<ConfigKey, ConfigValues>;
  28. // Dynamic import to avoid loading database modules too early
  29. const { Config } = await import('../../models/config');
  30. const docs = await Config.find().exec();
  31. for (const doc of docs) {
  32. dbConfig[doc.key as ConfigKey] = {
  33. definition: (doc.key in CONFIG_DEFINITIONS) ? CONFIG_DEFINITIONS[doc.key as ConfigKey] : undefined,
  34. value: doc.value != null ? JSON.parse(doc.value) : null,
  35. };
  36. }
  37. logger.debug('loadFromDB', dbConfig);
  38. return dbConfig;
  39. }
  40. private parseEnvValue(value: string, type: string): unknown {
  41. switch (type) {
  42. case 'number':
  43. return parseInt(value, 10);
  44. case 'boolean':
  45. return toBoolean(value);
  46. case 'string':
  47. return value;
  48. case 'object':
  49. try {
  50. return JSON.parse(value);
  51. }
  52. catch {
  53. return null;
  54. }
  55. default:
  56. return value;
  57. }
  58. }
  59. }