Introduce config module

This commit is contained in:
Akihiko Odaki 2018-04-02 13:15:53 +09:00
parent a9c0dd5e53
commit 8b3407e16c
50 changed files with 213 additions and 208 deletions

View file

@ -24,7 +24,7 @@ const uglifyes = require('uglify-es');
import { fa } from './src/build/fa';
import version from './src/version';
import config from './src/conf';
import config from './src/config';
const uglify = uglifyComposer(uglifyes, console);

View file

@ -13,7 +13,7 @@ import * as mkdirp from 'mkdirp';
import locales from '../../../../locales';
import I18nReplacer from '../../../build/i18n';
import fa from '../../../build/fa';
import config from './../../../conf';
import config from './../../../config';
import generateVars from '../vars';

View file

@ -6,7 +6,7 @@ import * as licenseChecker from 'license-checker';
import * as tmp from 'tmp';
import { fa } from '../../build/fa';
import config from '../../conf';
import config from '../../config';
import { licenseHtml } from '../../build/license';
const constants = require('../../const.json');

View file

@ -1,3 +0,0 @@
import load from './config';
export default load();

View file

@ -1,154 +0,0 @@
/**
* Config loader
*/
import * as fs from 'fs';
import { URL } from 'url';
import * as yaml from 'js-yaml';
import isUrl = require('is-url');
/**
* Path of configuration directory
*/
const dir = `${__dirname}/../.config`;
/**
* Path of configuration file
*/
export const path = process.env.NODE_ENV == 'test'
? `${dir}/test.yml`
: `${dir}/default.yml`;
/**
*
*/
type Source = {
/**
*
*/
maintainer: {
/**
*
*/
name: string;
/**
* (URLかmailto形式のURL)
*/
url: string;
};
url: string;
port: number;
https?: { [x: string]: string };
mongodb: {
host: string;
port: number;
db: string;
user: string;
pass: string;
};
redis: {
host: string;
port: number;
pass: string;
};
elasticsearch: {
enable: boolean;
host: string;
port: number;
pass: string;
};
recaptcha: {
site_key: string;
secret_key: string;
};
accesslog?: string;
accesses?: {
enable: boolean;
port: number;
};
twitter?: {
consumer_key: string;
consumer_secret: string;
};
github_bot?: {
hook_secret: string;
username: string;
};
othello_ai?: {
id: string;
i: string;
};
line_bot?: {
channel_secret: string;
channel_access_token: string;
};
analysis?: {
mecab_command?: string;
};
/**
* Service Worker
*/
sw?: {
public_key: string;
private_key: string;
};
google_maps_api_key: string;
};
/**
* Misskeyが自動的に()
*/
type Mixin = {
host: string;
hostname: string;
scheme: string;
ws_scheme: string;
api_url: string;
ws_url: string;
auth_url: string;
docs_url: string;
stats_url: string;
status_url: string;
dev_url: string;
drive_url: string;
};
export type Config = Source & Mixin;
export default function load() {
const config = yaml.safeLoad(fs.readFileSync(path, 'utf-8')) as Source;
const mixin = {} as Mixin;
// Validate URLs
if (!isUrl(config.url)) urlError(config.url);
const url = new URL(config.url);
config.url = normalizeUrl(config.url);
mixin.host = url.host;
mixin.hostname = url.hostname;
mixin.scheme = url.protocol.replace(/:$/, '');
mixin.ws_scheme = mixin.scheme.replace('http', 'ws');
mixin.ws_url = `${mixin.ws_scheme}://${mixin.host}`;
mixin.api_url = `${mixin.scheme}://${mixin.host}/api`;
mixin.auth_url = `${mixin.scheme}://${mixin.host}/auth`;
mixin.dev_url = `${mixin.scheme}://${mixin.host}/dev`;
mixin.docs_url = `${mixin.scheme}://${mixin.host}/docs`;
mixin.stats_url = `${mixin.scheme}://${mixin.host}/stats`;
mixin.status_url = `${mixin.scheme}://${mixin.host}/status`;
mixin.drive_url = `${mixin.scheme}://${mixin.host}/files`;
return Object.assign(config, mixin);
}
function normalizeUrl(url: string) {
return url[url.length - 1] === '/' ? url.substr(0, url.length - 1) : url;
}
function urlError(url: string) {
console.error(`${url}」は、正しいURLではありません。先頭に http:// または https:// をつけ忘れてないかなど確認してください。`);
process.exit();
}

3
src/config/index.ts Normal file
View file

@ -0,0 +1,3 @@
import load from './load';
export default load();

57
src/config/load.ts Normal file
View file

@ -0,0 +1,57 @@
/**
* Config loader
*/
import * as fs from 'fs';
import { URL } from 'url';
import * as yaml from 'js-yaml';
import { Source, Mixin } from './types';
import isUrl = require('is-url');
/**
* Path of configuration directory
*/
const dir = `${__dirname}/../../.config`;
/**
* Path of configuration file
*/
const path = process.env.NODE_ENV == 'test'
? `${dir}/test.yml`
: `${dir}/default.yml`;
export default function load() {
const config = yaml.safeLoad(fs.readFileSync(path, 'utf-8')) as Source;
const mixin = {} as Mixin;
// Validate URLs
if (!isUrl(config.url)) urlError(config.url);
const url = new URL(config.url);
config.url = normalizeUrl(config.url);
mixin.host = url.host;
mixin.hostname = url.hostname;
mixin.scheme = url.protocol.replace(/:$/, '');
mixin.ws_scheme = mixin.scheme.replace('http', 'ws');
mixin.ws_url = `${mixin.ws_scheme}://${mixin.host}`;
mixin.api_url = `${mixin.scheme}://${mixin.host}/api`;
mixin.auth_url = `${mixin.scheme}://${mixin.host}/auth`;
mixin.dev_url = `${mixin.scheme}://${mixin.host}/dev`;
mixin.docs_url = `${mixin.scheme}://${mixin.host}/docs`;
mixin.stats_url = `${mixin.scheme}://${mixin.host}/stats`;
mixin.status_url = `${mixin.scheme}://${mixin.host}/status`;
mixin.drive_url = `${mixin.scheme}://${mixin.host}/files`;
return Object.assign(config, mixin);
}
function normalizeUrl(url: string) {
return url[url.length - 1] === '/' ? url.substr(0, url.length - 1) : url;
}
function urlError(url: string) {
console.error(`${url}」は、正しいURLではありません。先頭に http:// または https:// をつけ忘れてないかなど確認してください。`);
process.exit();
}

97
src/config/types.ts Normal file
View file

@ -0,0 +1,97 @@
/**
*
*/
export type Source = {
/**
*
*/
maintainer: {
/**
*
*/
name: string;
/**
* (URLかmailto形式のURL)
*/
url: string;
};
url: string;
port: number;
https?: { [x: string]: string };
mongodb: {
host: string;
port: number;
db: string;
user: string;
pass: string;
};
redis: {
host: string;
port: number;
pass: string;
};
elasticsearch: {
enable: boolean;
host: string;
port: number;
pass: string;
};
recaptcha: {
site_key: string;
secret_key: string;
};
accesslog?: string;
accesses?: {
enable: boolean;
port: number;
};
twitter?: {
consumer_key: string;
consumer_secret: string;
};
github_bot?: {
hook_secret: string;
username: string;
};
othello_ai?: {
id: string;
i: string;
};
line_bot?: {
channel_secret: string;
channel_access_token: string;
};
analysis?: {
mecab_command?: string;
};
/**
* Service Worker
*/
sw?: {
public_key: string;
private_key: string;
};
google_maps_api_key: string;
};
/**
* Misskeyが自動的に()
*/
export type Mixin = {
host: string;
hostname: string;
scheme: string;
ws_scheme: string;
api_url: string;
ws_url: string;
auth_url: string;
docs_url: string;
stats_url: string;
status_url: string;
dev_url: string;
drive_url: string;
};
export type Config = Source & Mixin;

View file

@ -1,5 +1,5 @@
import * as elasticsearch from 'elasticsearch';
import config from '../conf';
import config from '../config';
// Init ElasticSearch connection
const client = new elasticsearch.Client({

View file

@ -1,4 +1,4 @@
import config from '../conf';
import config from '../config';
const u = config.mongodb.user ? encodeURIComponent(config.mongodb.user) : null;
const p = config.mongodb.pass ? encodeURIComponent(config.mongodb.pass) : null;

View file

@ -1,5 +1,5 @@
import * as redis from 'redis';
import config from '../conf';
import config from '../config';
export default redis.createClient(
config.redis.port,

View file

@ -15,7 +15,7 @@ import DriveFolder from '../models/drive-folder';
import { pack } from '../models/drive-file';
import event, { publishDriveStream } from '../event';
import getAcct from '../user/get-acct';
import config from '../conf';
import config from '../config';
const gm = _gm.subClass({
imageMagick: true

View file

@ -1,7 +1,7 @@
import * as mongo from 'mongodb';
import * as redis from 'redis';
import swPush from './push-sw';
import config from './conf';
import config from './config';
type ID = string | mongo.ObjectID;

View file

@ -4,7 +4,6 @@
Error.stackTraceLimit = Infinity;
import * as fs from 'fs';
import * as os from 'os';
import * as cluster from 'cluster';
import * as debug from 'debug';
@ -21,8 +20,8 @@ import MachineInfo from './utils/machineInfo';
import DependencyInfo from './utils/dependencyInfo';
import stats from './utils/stats';
import { Config, path as configPath } from './config';
import loadConfig from './config';
import loadConfig from './config/load';
import { Config } from './config/types';
import parseOpt from './parse-opt';
@ -116,11 +115,17 @@ async function init(): Promise<Config> {
new DependencyInfo().showAll();
const configLogger = new Logger('Config');
if (!fs.existsSync(configPath)) {
throw 'Configuration not found - Please run "npm run config" command.';
}
let config;
const config = loadConfig();
try {
config = loadConfig();
} catch (exception) {
if (exception.code === 'ENOENT') {
throw 'Configuration not found - Please run "npm run config" command.';
}
throw exception;
}
configLogger.info('Successfully loaded');
configLogger.info(`maintainer: ${config.maintainer}`);

View file

@ -2,7 +2,7 @@ import * as mongo from 'mongodb';
import deepcopy = require('deepcopy');
import AccessToken from './access-token';
import db from '../db/mongodb';
import config from '../conf';
import config from '../config';
const App = db.get<IApp>('apps');
App.createIndex('nameId');

View file

@ -1,7 +1,7 @@
import * as mongodb from 'mongodb';
import deepcopy = require('deepcopy');
import { pack as packFolder } from './drive-folder';
import config from '../conf';
import config from '../config';
import monkDb, { nativeDbConn } from '../db/mongodb';
const DriveFile = monkDb.get<IDriveFile>('driveFiles.files');

View file

@ -6,7 +6,7 @@ import { IPost, pack as packPost } from './post';
import Following from './following';
import Mute from './mute';
import getFriends from '../server/api/common/get-friends';
import config from '../conf';
import config from '../config';
const User = db.get<IUser>('users');

View file

@ -8,7 +8,7 @@
import * as request from 'request-promise-native';
import Othello, { Color } from '../core';
import conf from '../../conf';
import conf from '../../config';
let game;
let form;

View file

@ -10,7 +10,7 @@ import * as childProcess from 'child_process';
const WebSocket = require('ws');
import * as ReconnectingWebSocket from 'reconnecting-websocket';
import * as request from 'request-promise-native';
import conf from '../../conf';
import conf from '../../config';
// 設定 ////////////////////////////////////////////////////////

View file

@ -7,7 +7,7 @@ import event from '../../event';
import notify from '../../notify';
import context from '../../remote/activitypub/renderer/context';
import render from '../../remote/activitypub/renderer/follow';
import config from '../../conf';
import config from '../../config';
export default ({ data }, done) => Following.findOne({ _id: data.following }).then(({ followerId, followeeId }) => {
const promisedFollower: Promise<ILocalUser> = User.findOne({ _id: followerId });

View file

@ -1,7 +1,7 @@
const push = require('web-push');
import * as mongo from 'mongodb';
import Subscription from './models/sw-subscription';
import config from './conf';
import config from './config';
if (config.sw) {
// アプリケーションの連絡先と、サーバーサイドの鍵ペアの情報を登録

View file

@ -1,5 +1,5 @@
import { createQueue } from 'kue';
import config from './conf';
import config from './config';
export default createQueue({
redis: {

View file

@ -1,5 +1,5 @@
import { JSDOM } from 'jsdom';
import config from '../../conf';
import config from '../../config';
import Post from '../../models/post';
import RemoteUserObject, { IRemoteUserObject } from '../../models/remote-user-object';
import uploadFromUrl from '../../drive/upload-from-url';

View file

@ -1,4 +1,4 @@
import config from '../../../conf';
import config from '../../../config';
export default ({ _id, contentType }) => ({
type: 'Document',

View file

@ -1,4 +1,4 @@
import config from '../../../conf';
import config from '../../../config';
import { IRemoteUser } from '../../../models/user';
export default ({ username }, followee: IRemoteUser) => ({

View file

@ -1,4 +1,4 @@
import config from '../../../conf';
import config from '../../../config';
export default tag => ({
type: 'Hashtag',

View file

@ -1,4 +1,4 @@
import config from '../../../conf';
import config from '../../../config';
export default ({ _id }) => ({
type: 'Image',

View file

@ -1,4 +1,4 @@
import config from '../../../conf';
import config from '../../../config';
import { extractPublic } from '../../../crypto_key';
import { ILocalUser } from '../../../models/user';

View file

@ -1,6 +1,6 @@
import renderDocument from './document';
import renderHashtag from './hashtag';
import config from '../../../conf';
import config from '../../../config';
import DriveFile from '../../../models/drive-file';
import Post from '../../../models/post';
import User from '../../../models/user';

View file

@ -1,6 +1,6 @@
import renderImage from './image';
import renderKey from './key';
import config from '../../../conf';
import config from '../../../config';
export default user => {
const id = `${config.url}/@${user.username}`;

View file

@ -2,7 +2,7 @@ import * as express from 'express';
import context from '../../remote/activitypub/renderer/context';
import renderNote from '../../remote/activitypub/renderer/note';
import renderOrderedCollection from '../../remote/activitypub/renderer/ordered-collection';
import config from '../../conf';
import config from '../../config';
import Post from '../../models/post';
import withUser from './with-user';

View file

@ -1,7 +1,7 @@
import * as express from 'express';
import context from '../../remote/activitypub/renderer/context';
import render from '../../remote/activitypub/renderer/key';
import config from '../../conf';
import config from '../../config';
import withUser from './with-user';
const app = express();

View file

@ -1,5 +1,5 @@
import * as express from 'express';
import config from '../../conf';
import config from '../../config';
import context from '../../remote/activitypub/renderer/context';
import render from '../../remote/activitypub/renderer/person';
import withUser from './with-user';

View file

@ -3,7 +3,7 @@ import * as express from 'express';
import * as request from 'request';
import * as crypto from 'crypto';
import User from '../../../../models/user';
import config from '../../../../conf';
import config from '../../../../config';
import BotCore from '../core';
import _redis from '../../../../db/redis';
import prominence = require('prominence');

View file

@ -1,4 +1,4 @@
import config from '../../../conf';
import config from '../../../config';
export default function(res, user, redirect: boolean) {
const expires = 1000 * 60 * 60 * 24 * 365; // One Year

View file

@ -5,7 +5,7 @@ import * as uuid from 'uuid';
import $ from 'cafy';
import App from '../../../../../models/app';
import AuthSess from '../../../../../models/auth-session';
import config from '../../../../../conf';
import config from '../../../../../config';
/**
* @swagger

View file

@ -6,7 +6,7 @@ import * as bcrypt from 'bcryptjs';
import * as speakeasy from 'speakeasy';
import * as QRCode from 'qrcode';
import User from '../../../../../models/user';
import config from '../../../../../conf';
import config from '../../../../../config';
module.exports = async (params, user) => new Promise(async (res, rej) => {
// Get 'password' parameter

View file

@ -4,7 +4,7 @@
import $ from 'cafy';
import User, { isValidName, isValidDescription, isValidLocation, isValidBirthday, pack } from '../../../../models/user';
import event from '../../../../event';
import config from '../../../../conf';
import config from '../../../../config';
/**
* Update myself

View file

@ -13,7 +13,7 @@ import publishUserStream from '../../../../../event';
import { publishMessagingStream, publishMessagingIndexStream, pushSw } from '../../../../../event';
import html from '../../../../../text/html';
import parse from '../../../../../text/parse';
import config from '../../../../../conf';
import config from '../../../../../config';
/**
* Create a message

View file

@ -3,7 +3,7 @@
*/
import * as os from 'os';
import version from '../../../version';
import config from '../../../conf';
import config from '../../../config';
import Meta from '../../../models/meta';
/**

View file

@ -19,7 +19,7 @@ import event, { pushSw, publishChannelStream } from '../../../../event';
import notify from '../../../../notify';
import getAcct from '../../../../user/get-acct';
import parseAcct from '../../../../user/parse-acct';
import config from '../../../../conf';
import config from '../../../../config';
/**
* Create a post

View file

@ -4,7 +4,7 @@
import * as mongo from 'mongodb';
import $ from 'cafy';
import User, { pack } from '../../../../models/user';
import config from '../../../../conf';
import config from '../../../../config';
const escapeRegexp = require('escape-regexp');
/**

View file

@ -5,7 +5,7 @@ import User, { ILocalUser } from '../../../models/user';
import Signin, { pack } from '../../../models/signin';
import event from '../../../event';
import signin from '../common/signin';
import config from '../../../conf';
import config from '../../../config';
export default async (req: express.Request, res: express.Response) => {
res.header('Access-Control-Allow-Origin', config.url);

View file

@ -5,7 +5,7 @@ import { generate as generateKeypair } from '../../../crypto_key';
import recaptcha = require('recaptcha-promise');
import User, { IUser, validateUsername, validatePassword, pack } from '../../../models/user';
import generateUserToken from '../common/generate-native-user-token';
import config from '../../../conf';
import config from '../../../config';
recaptcha.init({
secret_key: config.recaptcha.secret_key

View file

@ -2,7 +2,7 @@ import * as EventEmitter from 'events';
import * as express from 'express';
//const crypto = require('crypto');
import User from '../../../models/user';
import config from '../../../conf';
import config from '../../../config';
import queue from '../../../queue';
module.exports = async (app: express.Application) => {

View file

@ -7,7 +7,7 @@ import autwh from 'autwh';
import redis from '../../../db/redis';
import User, { pack } from '../../../models/user';
import event from '../../../event';
import config from '../../../conf';
import config from '../../../config';
import signin from '../common/signin';
module.exports = (app: express.Application) => {

View file

@ -1,7 +1,7 @@
import * as http from 'http';
import * as websocket from 'websocket';
import * as redis from 'redis';
import config from '../../conf';
import config from '../../config';
import { default as User, IUser } from '../../models/user';
import AccessToken from '../../models/access-token';
import isNativeToken from './common/is-native-token';

View file

@ -12,7 +12,7 @@ import Accesses from 'accesses';
import activityPub from './activitypub';
import webFinger from './webfinger';
import log from './log-request';
import config from '../conf';
import config from '../config';
/**
* Init app

View file

@ -1,4 +1,4 @@
import config from '../conf';
import config from '../config';
import parseAcct from '../user/parse-acct';
import User from '../models/user';
const express = require('express');

View file

@ -14,7 +14,7 @@ const ProgressBarPlugin = require('progress-bar-webpack-plugin');
import I18nReplacer from './src/build/i18n';
import { pattern as faPattern, replacement as faReplacement } from './src/build/fa';
const constants = require('./src/const.json');
import config from './src/conf';
import config from './src/config';
import { licenseHtml } from './src/build/license';
import locales from './locales';