2018-04-02 13:15:53 +09:00
|
|
|
/**
|
|
|
|
* Config loader
|
|
|
|
*/
|
|
|
|
|
|
|
|
import * as fs from 'fs';
|
|
|
|
import { URL } from 'url';
|
2019-02-06 22:44:55 +09:00
|
|
|
import $ from 'cafy';
|
2018-04-02 13:15:53 +09:00
|
|
|
import * as yaml from 'js-yaml';
|
2019-01-31 01:08:43 +09:00
|
|
|
import * as pkg from '../../package.json';
|
2019-02-06 22:44:55 +09:00
|
|
|
import { fromNullable } from '../prelude/maybe';
|
2018-04-02 13:15:53 +09:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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() {
|
2019-02-06 22:44:55 +09:00
|
|
|
const config = yaml.safeLoad(fs.readFileSync(path, 'utf-8'));
|
2018-04-02 13:15:53 +09:00
|
|
|
|
2019-02-06 22:44:55 +09:00
|
|
|
if (typeof config.url !== 'string') {
|
|
|
|
throw 'You need to configure the URL.';
|
|
|
|
}
|
2018-04-02 13:15:53 +09:00
|
|
|
|
2019-02-04 00:09:24 +09:00
|
|
|
const url = validateUrl(config.url);
|
2019-02-06 22:44:55 +09:00
|
|
|
|
|
|
|
if (typeof config.port !== 'number') {
|
|
|
|
throw 'You need to configure the port.';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config.https != null) {
|
|
|
|
if (typeof config.https.key !== 'string') {
|
|
|
|
throw 'You need to configure the https key.';
|
|
|
|
}
|
|
|
|
if (typeof config.https.cert !== 'string') {
|
|
|
|
throw 'You need to configure the https cert.';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config.mongodb == null) {
|
|
|
|
throw 'You need to configure the MongoDB.';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof config.mongodb.host !== 'string') {
|
|
|
|
throw 'You need to configure the MongoDB host.';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof config.mongodb.port !== 'number') {
|
|
|
|
throw 'You need to configure the MongoDB port.';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof config.mongodb.db !== 'string') {
|
|
|
|
throw 'You need to configure the MongoDB database name.';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config.drive == null) {
|
|
|
|
throw 'You need to configure the drive.';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof config.drive.storage !== 'string') {
|
|
|
|
throw 'You need to configure the drive storage type.';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$.str.or(['db', 'minio']).ok(config.drive.storage)) {
|
|
|
|
throw 'Unrecognized drive storage type is specified.';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config.drive.storage === 'minio') {
|
2019-02-07 20:14:15 +09:00
|
|
|
if (typeof config.drive.bucket !== 'string') {
|
2019-02-06 22:44:55 +09:00
|
|
|
throw 'You need to configure the minio bucket.';
|
|
|
|
}
|
|
|
|
|
2019-02-07 20:14:15 +09:00
|
|
|
if (typeof config.drive.prefix !== 'string') {
|
2019-02-06 22:44:55 +09:00
|
|
|
throw 'You need to configure the minio prefix.';
|
|
|
|
}
|
|
|
|
|
2019-02-07 20:14:15 +09:00
|
|
|
if (config.drive.prefix.config == null) {
|
2019-02-06 22:44:55 +09:00
|
|
|
throw 'You need to configure the minio.';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config.redis != null) {
|
|
|
|
if (typeof config.redis.host !== 'string') {
|
|
|
|
throw 'You need to configure the Redis host.';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof config.redis.port !== 'number') {
|
|
|
|
throw 'You need to configure the Redis port.';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config.elasticsearch != null) {
|
|
|
|
if (typeof config.elasticsearch.host !== 'string') {
|
|
|
|
throw 'You need to configure the Elasticsearch host.';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof config.elasticsearch.port !== 'number') {
|
|
|
|
throw 'You need to configure the Elasticsearch port.';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const source = {
|
|
|
|
url: normalizeUrl(config.url as string),
|
|
|
|
port: config.port as number,
|
|
|
|
https: fromNullable(config.https).map(x => ({
|
|
|
|
key: x.key as string,
|
|
|
|
cert: x.cert as string,
|
|
|
|
ca: fromNullable<string>(x.ca)
|
|
|
|
})),
|
|
|
|
mongodb: {
|
|
|
|
host: config.mongodb.host as string,
|
|
|
|
port: config.mongodb.port as number,
|
|
|
|
db: config.mongodb.db as string,
|
|
|
|
user: fromNullable<string>(config.mongodb.user),
|
|
|
|
pass: fromNullable<string>(config.mongodb.pass)
|
|
|
|
},
|
|
|
|
redis: fromNullable(config.redis).map(x => ({
|
|
|
|
host: x.host as string,
|
|
|
|
port: x.port as number,
|
|
|
|
pass: fromNullable<string>(x.pass)
|
|
|
|
})),
|
|
|
|
elasticsearch: fromNullable(config.elasticsearch).map(x => ({
|
|
|
|
host: x.host as string,
|
|
|
|
port: x.port as number,
|
|
|
|
pass: fromNullable<string>(x.pass)
|
|
|
|
})),
|
|
|
|
disableHsts: typeof config.disableHsts === 'boolean' ? config.disableHsts as boolean : false,
|
|
|
|
drive: {
|
|
|
|
storage: config.drive.storage as string,
|
|
|
|
bucket: config.drive.bucket as string,
|
|
|
|
prefix: config.drive.prefix as string,
|
|
|
|
baseUrl: fromNullable<string>(config.drive.baseUrl),
|
|
|
|
config: config.drive.config
|
|
|
|
},
|
|
|
|
autoAdmin: typeof config.autoAdmin === 'boolean' ? config.autoAdmin as boolean : false,
|
|
|
|
proxy: fromNullable<string>(config.proxy),
|
|
|
|
clusterLimit: typeof config.clusterLimit === 'number' ? config.clusterLimit as number : Infinity,
|
|
|
|
};
|
|
|
|
|
|
|
|
const host = url.host;
|
|
|
|
const scheme = url.protocol.replace(/:$/, '');
|
|
|
|
const ws_scheme = scheme.replace('http', 'ws');
|
|
|
|
|
|
|
|
const mixin = {
|
|
|
|
host: url.host,
|
|
|
|
hostname: url.hostname,
|
|
|
|
scheme: scheme,
|
|
|
|
ws_scheme: ws_scheme,
|
|
|
|
ws_url: `${ws_scheme}://${host}`,
|
|
|
|
api_url: `${scheme}://${host}/api`,
|
|
|
|
auth_url: `${scheme}://${host}/auth`,
|
|
|
|
dev_url: `${scheme}://${host}/dev`,
|
|
|
|
docs_url: `${scheme}://${host}/docs`,
|
|
|
|
stats_url: `${scheme}://${host}/stats`,
|
|
|
|
status_url: `${scheme}://${host}/status`,
|
|
|
|
drive_url: `${scheme}://${host}/files`,
|
|
|
|
user_agent: `Misskey/${pkg.version} (${config.url})`
|
|
|
|
};
|
|
|
|
|
|
|
|
return Object.assign(source, mixin);
|
2018-04-02 13:15:53 +09:00
|
|
|
}
|
|
|
|
|
2019-02-06 13:37:20 +09:00
|
|
|
function tryCreateUrl(url: string) {
|
2019-02-04 00:09:24 +09:00
|
|
|
try {
|
|
|
|
return new URL(url);
|
|
|
|
} catch (e) {
|
2019-02-06 13:37:20 +09:00
|
|
|
throw `url="${url}" is not a valid URL.`;
|
2019-02-04 00:09:24 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-06 13:37:20 +09:00
|
|
|
function validateUrl(url: string) {
|
|
|
|
const result = tryCreateUrl(url);
|
|
|
|
if (result.pathname.replace('/', '').length) throw `url="${url}" is not a valid URL, has a pathname.`;
|
|
|
|
if (!url.includes(result.host)) throw `url="${url}" is not a valid URL, has an invalid hostname.`;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-04-02 13:15:53 +09:00
|
|
|
function normalizeUrl(url: string) {
|
2018-08-26 13:55:39 +09:00
|
|
|
return url.endsWith('/') ? url.substr(0, url.length - 1) : url;
|
2018-04-02 13:15:53 +09:00
|
|
|
}
|