| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- 'use strict'
-
- import { getLogger, Logger, } from "log4js";
- import { promises as fs, mkdirSync } from "fs"
- import { RPCServer } from 'rpclibrary'
- import * as Path from 'path'
- import * as Knex from 'knex';
- import * as http from 'http';
- import * as express from 'express';
- import { existsSync } from "fs";
- import { GuildManager } from '../Components/Guild/GuildManager';
- import { ItemManager } from '../Components/Item/ItemManager';
- import { RaidManager } from '../Components/Raid/RaidManager';
- import { CharacterManager } from '../Components/Character/CharacterManager';
- import { UserManager } from '../Components/User/UserManager';
- import { RootComponent } from '../Injector/ServiceDecorator';
- import { TableDefinitionExporter } from '../Types/Interfaces';
- import { AdminConf, TableDefiniton } from '../Types/Types';
- import { RPCConfigLoader } from '../Components/RPCConfigLoader';
- import { FrontworkComponent } from '../Types/FrontworkComponent';
- import { IAdmin } from './Interface';
- import { Injector } from '../Injector/Injector';
- import { PubSub } from '../Components/PubSub/PubSub';
-
- @RootComponent({
- injectable: IAdmin,
- injects: [
- GuildManager,
- ItemManager,
- RaidManager,
- CharacterManager,
- UserManager,
- PubSub
- ]
- })
- export class FrontworkAdmin
- implements TableDefinitionExporter, IAdmin {
- knex: Knex
- config: RPCConfigLoader<AdminConf>
- rpcServer: RPCServer
-
- private express : express.Application
- private httpServer
-
- constructor(private frontworkComponents: FrontworkComponent[] = []) {
- this.config = new RPCConfigLoader<AdminConf>({
- name: "FrontworkAdminConf",
- getDefaultConfig: () => {
- return {
- httpPort: 8080,
- eventBusConf: {},
- dbConf: {
- client: 'sqlite3',
- connection: {
- filename: Path.resolve(__dirname, '../../../..', "data/frontworkAdmin.sqlite"),
- },
- migrations: {
- directory: Path.resolve(__dirname, '../../../..', "migrations"),
- extension: 'ts'
- },
- useNullAsDefault: true,
- }
- }
- }
- }, './config', this.configChangeHandler)
- }
-
- async start() {
- let port: number = this.config.getConfig().httpPort
-
- await this.makeKnex()
- const app = await this.makeExpress()
- const httpServer = new http.Server(app)
- await this.startWebsocket(httpServer)
- httpServer.listen(port)
- await this.attachAngularSSR(app)
- getLogger('Admin#startWebsocket').debug("Webserver up on", port)
-
- await Promise.all(this.frontworkComponents.map(c => c.initialize ? c.initialize() : undefined))
- getLogger('Admin#start').debug(this.frontworkComponents.length + " components initialized")
- }
-
- stop() {
- Promise.all([
- ...this.frontworkComponents.map(c => c.stop ? c.stop() : undefined),
- ])
- .catch(e => getLogger('Admin#stop').warn(e))
- .finally(() => {
- this.rpcServer.close()
- process.exit(0)
- })
- }
-
- protected configChangeHandler = (conf: AdminConf, key?: string) => {
- if (key === 'dbConf') {
- this.makeKnex()
- }
- }
-
- getConfigKey(key: string) {
- return this.config.getConfigKey(key)
- }
-
- setConfigKey(key: string, value: any) {
- return this.config.setConfigKey(key, value)
- }
-
- getTableDefinitions(): TableDefiniton[] {
- return [
- ...this.frontworkComponents
- ]
- .filter(exp => exp.getTableDefinitions != null)
- .flatMap(exp => exp.getTableDefinitions())
- }
-
- private startWebsocket(httpServer: http.Server) {
- this.rpcServer = new RPCServer([
- ...this.frontworkComponents,
- {
- name: "debug",
- RPCs: () => [{
- name: 'dumpDb',
- call: async (table) => await this.knex(table).select('*')
- }]
- }
- ], {
- errorHandler: (sock, err, rpc, args) => {
- console.log("RPC", rpc)
- console.log("ERR", err)
- console.log("ARGS", args)
- }
- })
- .attach(httpServer)
- }
-
- private async makeExpress() {
- if (this.httpServer != null || this.express != null) {
- getLogger('Admin#startWebserver').warn("Webserver is already running")
- return
- }
-
- this.express = express()
-
- const distFolder = "../../../../dist"
-
- this.express.get('*.*', (req, res) => {
- //console.log('*.*', req.path);
- try{
- const filepath = Path.join(__dirname, distFolder, 'browser', decodeURIComponent(req.path))
- if(!existsSync(filepath)){
- throw new Error("Bad file access: "+filepath)
- }
- res.sendFile(filepath)
- res.status(200)
- }catch(e){
- getLogger('Admin#startWebserver#serveFile').error(String(e))
- res.send("404 NOT FOUND")
- res.status(404)
- }
- })
-
- return this.express
- }
-
- attachAngularSSR = async (express : express.Application) => {
- const distFolder = "../../../../dist"
- const ngExpressServer = Path.join(__dirname, distFolder, 'server.js')
- let port: number = this.config.getConfig().httpPort
-
- try {
- const req = require(distFolder + "/server.js")
- await req.attachExpress(express, './dist', getLogger('angularSSR#'))
- getLogger('Admin#startWebserver').debug('Frontend from ' + ngExpressServer + " loaded")
- } catch (e) {
- getLogger('Admin#startWebserver').error(e)
- getLogger('Admin#startWebserver').warn("No angular SSR module was provided in " + ngExpressServer)
- getLogger('Admin#startWebserver').warn("This is not fatal, but your page will not render on *" + port)
- }
- }
-
- private stopWebserver() {
- if (this.httpServer == null || this.express == null) {
- getLogger('Admin#stopWebserver').warn("Webserver is not running")
- return
- }
- this.httpServer.close()
- this.httpServer = null
- this.express = null
- getLogger('Admin#stopWebserver').info("Webserver stopped")
- }
-
- async makeKnex(): Promise<Knex> {
- const conf: Knex.Config = this.config.getConfigKey("dbConf")
-
- getLogger('Admin#makeKnex').debug("Making new knex:", conf)
- if (conf.client === 'sqlite3') {
- mkdirSync(Path.dirname((<any>conf.connection).filename), { recursive: true })
- }
-
- this.knex = Knex(conf)
- if (conf.client === 'sqlite3') {
- await this.knex.raw('PRAGMA foreign_keys = ON');
-
- }
-
- await Promise.all(
- this.getTableDefinitions()
- //make unique by name
- .filter((other, index, self) => index === self.findIndex(
- (self) => self.name === other.name)
- )
- //create table if not exists
- .map(async (def) => {
- const hasTable = await this.knex.schema.hasTable(def.name)
- if (!hasTable)
- return await this.knex.schema.createTable(def.name, def.tableBuilder)
- })
- )
- await this.knex.migrate.latest().catch(e => {
- getLogger('Admin#makeKnex').error(e)
- process.exit(-1)
- })
- return this.knex
- }
- }
-
- process.on('SIGINT', function () {
- getLogger('process#SIGINT').info("Shutting down from SIGINT (Ctrl-C)");
- Injector.resolve<FrontworkAdmin>(FrontworkAdmin).stop()
- })
|