2023-07-27 07:31:52 +02:00
/ *
2024-02-13 16:59:27 +01:00
* SPDX - FileCopyrightText : syuilo and misskey - project
2023-07-27 07:31:52 +02:00
* SPDX - License - Identifier : AGPL - 3.0 - only
* /
2022-02-27 03:07:39 +01:00
import * as fs from 'node:fs' ;
import { fileURLToPath } from 'node:url' ;
import { dirname } from 'node:path' ;
import * as os from 'node:os' ;
import cluster from 'node:cluster' ;
import chalk from 'chalk' ;
import chalkTemplate from 'chalk-template' ;
2022-09-17 20:27:08 +02:00
import Logger from '@/logger.js' ;
import { loadConfig } from '@/config.js' ;
import type { Config } from '@/config.js' ;
2022-02-27 03:07:39 +01:00
import { showMachineInfo } from '@/misc/show-machine-info.js' ;
2023-01-23 12:07:48 +01:00
import { envOption } from '@/env.js' ;
import { jobQueue , server } from './common.js' ;
2021-08-20 14:34:56 +02:00
2022-02-27 03:07:39 +01:00
const _filename = fileURLToPath ( import . meta . url ) ;
2021-08-20 14:34:56 +02:00
const _dirname = dirname ( _filename ) ;
2021-11-11 18:02:25 +01:00
const meta = JSON . parse ( fs . readFileSync ( ` ${ _dirname } /../../../../built/meta.json ` , 'utf-8' ) ) ;
2019-04-07 14:50:36 +02:00
const logger = new Logger ( 'core' , 'cyan' ) ;
const bootLogger = logger . createSubLogger ( 'boot' , 'magenta' , false ) ;
2022-02-27 03:07:39 +01:00
const themeColor = chalk . hex ( '#86b300' ) ;
2019-11-24 09:11:53 +01:00
function greet() {
2021-10-08 14:24:05 +02:00
if ( ! envOption . quiet ) {
2019-04-07 14:50:36 +02:00
//#region Misskey logo
2019-11-24 09:11:53 +01:00
const v = ` v ${ meta . version } ` ;
2022-02-27 03:07:39 +01:00
console . log ( themeColor ( ' _____ _ _ ' ) ) ;
console . log ( themeColor ( ' | |_|___ ___| |_ ___ _ _ ' ) ) ;
console . log ( themeColor ( ' | | | | |_ -|_ -| \'_| -_| | |' ) ) ;
console . log ( themeColor ( ' |_|_|_|_|___|___|_,_|___|_ |' ) ) ;
2023-07-14 00:59:54 +02:00
console . log ( ' ' + chalk . gray ( v ) + themeColor ( ' |___|\n' . substring ( v . length ) ) ) ;
2019-04-07 14:50:36 +02:00
//#endregion
2020-02-01 09:16:17 +01:00
console . log ( ' Misskey is an open-source decentralized microblogging platform.' ) ;
2022-02-27 03:07:39 +01:00
console . log ( chalk . rgb ( 255 , 136 , 0 ) ( ' If you like Misskey, please donate to support development. https://www.patreon.com/syuilo' ) ) ;
2019-04-07 14:50:36 +02:00
console . log ( '' ) ;
2022-02-27 03:07:39 +01:00
console . log ( chalkTemplate ` --- ${ os . hostname ( ) } {gray (PID: ${ process . pid . toString ( ) } )} --- ` ) ;
2019-04-07 14:50:36 +02:00
}
bootLogger . info ( 'Welcome to Misskey!' ) ;
2019-11-24 09:11:53 +01:00
bootLogger . info ( ` Misskey v ${ meta . version } ` , null , true ) ;
2019-04-07 14:50:36 +02:00
}
/ * *
* Init master process
* /
export async function masterMain() {
2019-04-12 18:43:22 +02:00
let config ! : Config ;
2019-04-07 14:50:36 +02:00
2021-04-24 15:55:18 +02:00
// initialize app
2019-04-07 14:50:36 +02:00
try {
2019-11-24 09:11:53 +01:00
greet ( ) ;
2021-04-24 15:55:18 +02:00
showEnvironment ( ) ;
await showMachineInfo ( bootLogger ) ;
showNodejsVersion ( ) ;
config = loadConfigBoot ( ) ;
2022-09-17 20:27:08 +02:00
//await connectDb();
2023-09-27 02:32:36 +02:00
if ( config . pidFile ) fs . writeFileSync ( config . pidFile , process . pid . toString ( ) ) ;
2019-04-07 14:50:36 +02:00
} catch ( e ) {
bootLogger . error ( 'Fatal error occurred during initialization' , null , true ) ;
process . exit ( 1 ) ;
}
bootLogger . succ ( 'Misskey initialized' ) ;
2023-09-17 08:43:50 +02:00
if ( envOption . disableClustering ) {
if ( envOption . onlyServer ) {
await server ( ) ;
} else if ( envOption . onlyQueue ) {
await jobQueue ( ) ;
} else {
await server ( ) ;
await jobQueue ( ) ;
}
} else {
if ( envOption . onlyServer ) {
// nop
} else if ( envOption . onlyQueue ) {
// nop
} else {
await server ( ) ;
}
2019-04-07 14:50:36 +02:00
await spawnWorkers ( config . clusterLimit ) ;
}
2023-09-17 08:43:50 +02:00
if ( envOption . onlyQueue ) {
bootLogger . succ ( 'Queue started' , null , true ) ;
} else {
bootLogger . succ ( config . socket ? ` Now listening on socket ${ config . socket } on ${ config . url } ` : ` Now listening on port ${ config . port } on ${ config . url } ` , null , true ) ;
}
2019-04-07 14:50:36 +02:00
}
function showEnvironment ( ) : void {
const env = process . env . NODE_ENV ;
const logger = bootLogger . createSubLogger ( 'env' ) ;
2020-04-04 01:46:54 +02:00
logger . info ( typeof env === 'undefined' ? 'NODE_ENV is not set' : ` NODE_ENV: ${ env } ` ) ;
2019-04-07 14:50:36 +02:00
if ( env !== 'production' ) {
logger . warn ( 'The environment is not in production mode.' ) ;
logger . warn ( 'DO NOT USE FOR PRODUCTION PURPOSE!' , null , true ) ;
}
}
2021-04-24 15:55:18 +02:00
function showNodejsVersion ( ) : void {
2019-04-07 14:50:36 +02:00
const nodejsLogger = bootLogger . createSubLogger ( 'nodejs' ) ;
2022-03-19 17:34:45 +01:00
nodejsLogger . info ( ` Version ${ process . version } detected. ` ) ;
2021-04-24 15:55:18 +02:00
}
2019-04-07 14:50:36 +02:00
2021-04-24 15:55:18 +02:00
function loadConfigBoot ( ) : Config {
2019-04-07 14:50:36 +02:00
const configLogger = bootLogger . createSubLogger ( 'config' ) ;
let config ;
try {
config = loadConfig ( ) ;
} catch ( exception ) {
if ( typeof exception === 'string' ) {
configLogger . error ( exception ) ;
process . exit ( 1 ) ;
2022-09-23 23:45:44 +02:00
} else if ( ( exception as any ) . code === 'ENOENT' ) {
2019-04-07 14:50:36 +02:00
configLogger . error ( 'Configuration file not found' , null , true ) ;
process . exit ( 1 ) ;
}
throw exception ;
}
configLogger . succ ( 'Loaded' ) ;
2021-04-24 15:55:18 +02:00
return config ;
}
2022-09-17 20:27:08 +02:00
/ *
2021-04-24 15:55:18 +02:00
async function connectDb ( ) : Promise < void > {
2020-04-26 04:39:15 +02:00
const dbLogger = bootLogger . createSubLogger ( 'db' ) ;
2019-04-07 14:50:36 +02:00
// Try to connect to DB
try {
2020-04-26 04:39:15 +02:00
dbLogger . info ( 'Connecting...' ) ;
2019-04-07 14:50:36 +02:00
await initDb ( ) ;
2022-03-26 07:34:00 +01:00
const v = await db . query ( 'SHOW server_version' ) . then ( x = > x [ 0 ] . server_version ) ;
2020-04-26 04:39:15 +02:00
dbLogger . succ ( ` Connected: v ${ v } ` ) ;
2022-09-17 20:27:08 +02:00
} catch ( err ) {
2020-04-26 04:39:15 +02:00
dbLogger . error ( 'Cannot connect' , null , true ) ;
2022-09-17 20:27:08 +02:00
dbLogger . error ( err ) ;
2019-04-07 14:50:36 +02:00
process . exit ( 1 ) ;
}
2021-04-24 15:55:18 +02:00
}
2022-09-17 20:27:08 +02:00
* /
2019-04-07 14:50:36 +02:00
2022-09-17 20:27:08 +02:00
async function spawnWorkers ( limit = 1 ) {
2019-04-07 14:50:36 +02:00
const workers = Math . min ( limit , os . cpus ( ) . length ) ;
bootLogger . info ( ` Starting ${ workers } worker ${ workers === 1 ? '' : 's' } ... ` ) ;
await Promise . all ( [ . . . Array ( workers ) ] . map ( spawnWorker ) ) ;
bootLogger . succ ( 'All workers started' ) ;
}
function spawnWorker ( ) : Promise < void > {
return new Promise ( res = > {
const worker = cluster . fork ( ) ;
worker . on ( 'message' , message = > {
2022-05-19 04:49:07 +02:00
if ( message === 'listenFailed' ) {
2022-09-17 20:27:08 +02:00
bootLogger . error ( 'The server Listen failed due to the previous error.' ) ;
2022-05-19 04:49:07 +02:00
process . exit ( 1 ) ;
}
2019-04-07 14:50:36 +02:00
if ( message !== 'ready' ) return ;
res ( ) ;
} ) ;
} ) ;
}