Commit 3ba3d121 authored by Guillaume Lebigot's avatar Guillaume Lebigot

First try at modularization/multi-hostname KM Server

parent e857fe1b
Pipeline #10272 passed with stage
in 2 minutes and 18 seconds
......@@ -15,7 +15,7 @@ Make sure node and yarn are up to date
- node 10.13.0 or later
- yarn 1 or later
- PostgreSQL 10.6
- PostgreSQL 10.6 or later
Clone this repository and install dependencies
......@@ -74,21 +74,28 @@ For local use, please put this in your `config.yml` file :
```yaml
Frontend:
Host: localhost
Port: 1350
API:
Secure: false
Host: localhost
KaraExplorer:
Api: http://localhost:1350
Port: 1351
Host: localhost
Path: /base
Import:
Host: localhost
Path: /import
```
Explanations :
* Frontend.Host : Put your server's domain name. It's used by Express to know which domain to listen to and serve requests.
* Frontend.Port : Port you should access your KM Server at. Usually on nginx or Apache you'll proxy/reverse proxy requests coming from port 80 to this port
* KaraExplorer.Api : URL to the KM Server API. KM Explorer (the karaoke base browser) will use this URL to try to access the API to request data. Use https if necessary
* KaraExplorer.Port : Port on which KaraExplorer listens on. This is a separate port than Frontend.Port and should not be proxified at directly. KM Server will take care of routing stuff to and from KM Explorer
* KaraExplorer.Path : Path to the karaoke base. You cannot use / for this as it's used by the redirect service KM App uses.
- API.Host : Put your server's domain name. It's used by the API to know which domain to listen to and serve requests.
- API.Secure : Wether you're API is going to be on HTTPS or HTTP front server. Enabled by default, disable it for local tests without being behind a webserver
- Frontend.Port : Port you should access your KM Server at. Usually on nginx or Apache you'll proxy/reverse proxy requests coming from port 80 to this port
- KaraExplorer.Host : Host KMExplorer should be listening to
- KaraExplorer.Port : Port on which KMExplorer listens on. This is a separate port than Frontend.Port and should not be proxified at directly. KM Server will take care of routing stuff to and from KM Explorer
- KaraExplorer.Path : Path to the karaoke base. Use `/base` if it's the same host as your API.Host value so the shortener and your KMExplorer won't overlap.
- Import.Host and .Path : same as above, this is for the Karaoke Import submission form.
## Launch
......
......@@ -8,13 +8,13 @@ System:
Windows: ffmpeg.exe
OSX: ffmpeg
Repositories:
- Name: Change me
- Name: kara.moe
Online: false
Path:
Karas:
- app/data/karaokes
Lyrics:
- app/data/lyrics
- app/data/lyrics
Medias:
- app/data/medias
Series:
......@@ -22,12 +22,23 @@ System:
Tags:
- app/data/tags
Frontend:
Host: kara.moe
Port: 1350
API:
Secure: false
Host: localhost
Users:
Enabled: true
Shortener:
Enabled: true
Stats:
Enabled: true
KaraExplorer:
Api: http://localhost:1350
Port: 1351
Host: localhost
Path: /base
Import:
Host: localhost
Path: /import
Gitlab:
Enabled: true
Token: xxx
......
import logger from './lib/utils/logger';
import express, { Response } from 'express';
import express from 'express';
import {resolve} from 'path';
import bodyParser from 'body-parser';
import passport from 'passport';
......@@ -32,7 +32,11 @@ export function initFrontend(listenPort: number) {
const conf = getConfig();
const state = getState();
const app = express();
const mainApp = express();
const API = express();
const KMExplorer = express();
const KMImport = express();
const Shortener = express();
const KMServer = express();
app.set('trust proxy', (ip: string) => {
if (ip === '127.0.0.1' ||
......@@ -60,40 +64,58 @@ export function initFrontend(listenPort: number) {
? res.json()
: next();
});
app.use(vhost(`${conf.Frontend.Host}`, mainApp));
// KMExplorer
if (conf.KaraExplorer.Enabled) {
app.use(vhost(`${conf.KaraExplorer.Host}`, KMExplorer));
KMExplorer.use('/previews', express.static(resolvedPathPreviews()));
KMExplorer.use(conf.KaraExplorer.Path, proxy(`http://127.0.0.1:${conf.KaraExplorer.Port}`));
// fix bad behavior of next-i18next - language file are not prefixed correctly
KMExplorer.get('/static/locales/*', (req, res) => {
res.redirect(conf.KaraExplorer.Path + req.url);
return;
});
}
/** Disabled code for KM Rooms
app.use(vhost(`*.${conf.Frontend.Host}`, getKMRoom), proxy(redirectKMRoom, {
memoizeHost: false
}));
// Serve static files from the React app
mainApp.use('/base', proxy(`http://127.0.0.1:${conf.KaraExplorer.Port}`));
// fix bad behavior of next-i18next - language file are not prefixed correctly
mainApp.get('/static/locales/*', (req, res) => {
res.redirect('/base'+req.url);
return;
});
mainApp.use('/import', express.static(resolve(state.appPath, 'kmimport/build')));
mainApp.get('/import/*', (_, res) => {
*/
// KMImport
if (conf.Import.Enabled) {
app.use(vhost(`${conf.Import.Host}`, KMImport));
KMImport.use(conf.Import.Path, express.static(resolve(state.appPath, 'kmimport/build')));
KMImport.get(`${conf.Import.Path}/*`, (_, res) => {
res.sendFile(resolve(state.appPath, 'kmimport/build/index.html'));
});
});
}
//KMServer
// If static serve is enabled, we're serving all files from KMServer instead of Apache/nginx
if (state.opt.staticServe) {
mainApp.use('/downloads/karaokes', express.static(resolvedPathRepos('Karas')[0]));
mainApp.use('/downloads/lyrics', express.static(resolvedPathRepos('Lyrics')[0]));
mainApp.use('/downloads/medias', express.static(resolvedPathRepos('Medias')[0]));
mainApp.use('/downloads/series', express.static(resolvedPathRepos('Series')[0]));
mainApp.use('/downloads/tags', express.static(resolvedPathRepos('Tags')[0]));
KMServer.use('/downloads/karaokes', express.static(resolvedPathRepos('Karas')[0]));
KMServer.use('/downloads/lyrics', express.static(resolvedPathRepos('Lyrics')[0]));
KMServer.use('/downloads/medias', express.static(resolvedPathRepos('Medias')[0]));
KMServer.use('/downloads/series', express.static(resolvedPathRepos('Series')[0]));
KMServer.use('/downloads/tags', express.static(resolvedPathRepos('Tags')[0]));
}
mainApp.use('/previews', express.static(resolvedPathPreviews()));
mainApp.use('/avatars', express.static(resolvedPathAvatars()));
// API router
mainApp.use('/api', api());
mainApp.get('/', (_, res) => {
res.redirect('/api/shortener');
return;
});
app.use(vhost(`${conf.API.Host}`, API));
API.use('/api', api());
if (conf.Users.Enabled) API.use('/avatars', express.static(resolvedPathAvatars()));
if (conf.Shortener.Enabled) {
app.use(vhost(`${conf.API.Host}`, Shortener));
Shortener.get('/', (_, res) => {
res.redirect('/api/shortener');
return;
});
}
// The "catchall" handler: for any request that doesn't
// match one above, send back React's index.html file.
mainApp.get('*', (_, res) => res.status(404).send('Not found'));
app.get('*', (_, res) => res.status(404).send('Not found'));
const port = listenPort;
const server = createServer(app);
......@@ -103,26 +125,27 @@ export function initFrontend(listenPort: number) {
function api() {
const apiRouter = express.Router();
// Adding identification routes
authController(apiRouter);
const conf = getConfig();
// Adding admin routes
adminController(apiRouter);
// Adding KaraServ routes
KServerController(apiRouter);
KImportController(apiRouter);
if (conf.Import.Enabled) KImportController(apiRouter);
// Shortener/kara.moe route
shortenerController(apiRouter);
if (conf.Shortener.Enabled) shortenerController(apiRouter);
// Stats
statsController(apiRouter);
if (conf.Stats.Enabled) statsController(apiRouter);
// Online Mode for KM App
userController(apiRouter);
favoritesController(apiRouter);
if (conf.Users.Enabled) {
userController(apiRouter);
favoritesController(apiRouter);
authController(apiRouter);
}
return apiRouter;
}
/* This code is disabled until we get to host our own KM Apps on this server code
function getKMRoom(_req: any, _res: Response, next: any) {
/* This code is disabled until we get to host our own KM Apps on this server code
const instance = getInstanceRoom(req.vhost[0]);
if (!instance) {
......@@ -131,11 +154,10 @@ function getKMRoom(_req: any, _res: Response, next: any) {
req.KMAppPort = instance.port;
next();
}
*/
next();
}
function redirectKMRoom(req: any) {
return `http://localhost:${req.KMAppPort}`;
}
*/
\ No newline at end of file
......@@ -114,7 +114,7 @@ async function main() {
const inits = [];
kmExplorerStart({
api: conf.KaraExplorer.Api,
api: `${conf.API.Secure ? 'https://' : 'http://'}${conf.API.Host}${conf.Frontend.Port ? ':' + conf.Frontend.Port : ''}`,
port: conf.KaraExplorer.Port,
path: conf.KaraExplorer.Path,
});
......
Subproject commit 3d018d30694cdf9c2c48bf34d1c5235a5b00abbd
Subproject commit 1dd59a8a04c9a76660a26b7c197c037b658252b7
......@@ -22,14 +22,15 @@ export async function resetPasswordRequest(username: string) {
code: requestCode,
date: +(new Date().getTime() / 1000).toFixed(0)
});
const conf = getConfig();
sendMail('Karaoke Mugen Password Reset',`
Hello ${username},
You (or someone) requested a password reset for your account at ${getConfig().Frontend.Host}. If you didn't request this, please ignore this email.
You (or someone) requested a password reset for your account at ${getConfig().API.Host}. If you didn't request this, please ignore this email.
Please click the following link to get a new, randomized password sent to your mail account :
https://${getConfig().Frontend.Host}/api/users/${username}/resetpassword/${requestCode}
${conf.API.Secure ? 'https://' : 'http://'}${conf.API.Host}${conf.Frontend.Port ? ':'+conf.Frontend.Port : ''}/api/users/${username}/resetpassword/${requestCode}
This link will expire in two hours.
`,
......@@ -49,7 +50,7 @@ export async function resetPassword(username: string, requestCode: string) {
sendMail('Karaoke Mugen Password has been reset',`
Hello ${username},
You (or someone) requested a password reset for your account at ${getConfig().Frontend.Host}.
You (or someone) requested a password reset for your account at ${getConfig().API.Host}.
Your password has been reset to the following :
${newPassword}
......
......@@ -6,15 +6,34 @@ export interface Config {
InstanceID?: string,
},
Frontend: {
Host: string,
Port: number,
Port: number
SeriesLanguageMode: number
}
KaraExplorer: {
Api: string,
Port: number,
API: {
Secure: boolean
Host: string
}
Users: {
Enabled: boolean
}
Stats: {
Enabled: boolean
}
Shortener: {
Enabled: boolean
ExpireTimeDays: number
}
Import: {
Enabled: true
Host: string
Path: string
},
}
KaraExplorer: {
Enabled: boolean
Port: number
Host: string
Path: string
}
Gitlab?: {
Enabled?: boolean,
Host?: string,
......@@ -27,9 +46,6 @@ export interface Config {
KaraProblem?: GitlabTemplate
}
}
Shortener: {
ExpireTimeDays: number
},
System: {
Binaries: {
ffmpeg: {
......
import { Config } from "../types/config";
// Karaoke Mugen default configuration file
// this file is overwritten during updates, editing is ill-advised .
// you can change the default settings by using config.ini to bypass the default value .
export const defaults = {
export const defaults: Config = {
App: {
JwtSecret: 'Change me',
InstanceID: 'Change me',
......@@ -49,15 +51,31 @@ export const defaults = {
}
},
Shortener: {
Enabled: true,
ExpireTimeDays: 1
},
Frontend: {
Port: 1350,
Host: 'localhost',
SeriesLanguageMode: 3
},
Users: {
Enabled: true
},
Stats: {
Enabled: true
},
Import: {
Enabled: true,
Host: 'localhost',
Path: '/import'
},
API: {
Secure: true,
Host: 'localhost'
},
KaraExplorer: {
Api: 'http://localhost',
Enabled: true,
Host: 'localhost',
Port: 1351,
Path: '/base'
},
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment