Skip to content

Commit

Permalink
feat!: Merge (#44) API v2
Browse files Browse the repository at this point in the history
api v2
  • Loading branch information
KotRikD authored Feb 19, 2024
2 parents 407584b + fa6a7df commit ede27fc
Show file tree
Hide file tree
Showing 38 changed files with 2,306 additions and 452 deletions.
1 change: 1 addition & 0 deletions packages/common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"build": "tsc"
},
"dependencies": {
"@tosu/server": "workspace:*",
"dotenv": "^16.0.3",
"winston": "^3.8.2"
}
Expand Down
64 changes: 54 additions & 10 deletions packages/common/utils/config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Server } from '@tosu/server';
import * as dotenv from 'dotenv';
import fs from 'fs';
import path from 'path';

import { wLogger } from './logger';
import { configureLogger, wLogger } from './logger';

const configPath = path.join(path.dirname(process.execPath), 'tsosu.env');
if (!fs.existsSync(configPath)) {
Expand All @@ -23,8 +24,6 @@ ENABLE_KEY_OVERLAY=true
POLL_RATE=150
# Once per value, the programme should read the values of keys K1/K2/M1/M2 (in milliseconds)
KEYOVERLAY_POLL_RATE=150
# Once in what value, the programme should send information about values to the websocket (overlay) (in milliseconds)
WS_SEND_INTERVAL=150
# Enables/disables the in-game gosumemory overlay (!!!I AM NOT RESPONSIBLE FOR USING IT!!!).
ENABLE_GOSU_OVERLAY=false
Expand Down Expand Up @@ -52,7 +51,6 @@ export const config = {
debugLogging: (process.env.DEBUG_LOG || '') === 'true',
calculatePP: (process.env.CALCULATE_PP || '') === 'true',
enableKeyOverlay: (process.env.ENABLE_KEY_OVERLAY || '') === 'true',
wsSendInterval: Number(process.env.WS_SEND_INTERVAL || '500'),
pollRate: Number(process.env.POLL_RATE || '500'),
keyOverlayPollRate: Number(process.env.KEYOVERLAY_POLL_RATE || '100'),
serverIP: process.env.SERVER_IP || '127.0.0.1',
Expand All @@ -61,7 +59,7 @@ export const config = {
enableGosuOverlay: (process.env.ENABLE_GOSU_OVERLAY || '') === 'true'
};

export const updateConfig = () => {
export const updateConfigFile = () => {
let newOptions = '';

if (!process.env.DEBUG_LOG) {
Expand All @@ -79,11 +77,6 @@ export const updateConfig = () => {
fs.appendFileSync(configPath, '\nENABLE_KEY_OVERLAY=true', 'utf8');
}

if (!process.env.WS_SEND_INTERVAL) {
newOptions += 'WS_SEND_INTERVAL, ';
fs.appendFileSync(configPath, '\nWS_SEND_INTERVAL=150', 'utf8');
}

if (!process.env.POLL_RATE) {
newOptions += 'POLL_RATE, ';
fs.appendFileSync(configPath, '\nPOLL_RATE=150', 'utf8');
Expand Down Expand Up @@ -117,3 +110,54 @@ export const updateConfig = () => {
if (newOptions !== '')
wLogger.warn(`New options available in config: ${newOptions}\n`);
};

export const watchConfigFile = ({ httpServer }: { httpServer: Server }) => {
configureLogger();

refreshConfig(httpServer, false);
updateConfigFile();

fs.watchFile(configPath, (current, previous) => {
refreshConfig(httpServer, true);
});
};

export const refreshConfig = (httpServer: Server, refresh: boolean) => {
const status = refresh == true ? 'reload' : 'load';

const { parsed, error } = dotenv.config({ path: configPath });
if (error != null || parsed == null) {
wLogger.error(`Config ${status} failed`);
return;
}

const debugLogging = (parsed.DEBUG_LOG || '') === 'true';

const serverIP = parsed.SERVER_IP || '127.0.0.1';
const serverPort = Number(parsed.SERVER_PORT || '24050');

if (config.serverIP != serverIP || config.serverPort != serverPort) {
config.serverIP = serverIP;
config.serverPort = serverPort;

httpServer.restart();
}

config.debugLogging = debugLogging;
config.calculatePP = (parsed.CALCULATE_PP || '') === 'true';
config.enableKeyOverlay = (parsed.ENABLE_KEY_OVERLAY || '') === 'true';
config.pollRate = Number(parsed.POLL_RATE || '500');
config.keyOverlayPollRate = Number(parsed.KEYOVERLAY_POLL_RATE || '100');
config.staticFolderPath = parsed.STATIC_FOLDER_PATH || './static';
config.enableGosuOverlay = (parsed.ENABLE_GOSU_OVERLAY || '') === 'true';

if (
config.staticFolderPath == './static' &&
!fs.existsSync(path.join(process.cwd(), 'static'))
) {
fs.mkdirSync(path.join(process.cwd(), 'static'));
}

wLogger.info(`Config ${status}ed`);
configureLogger();
};
81 changes: 79 additions & 2 deletions packages/server/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,80 @@
import { config } from '@tosu/common';

import buildBaseApi from './router/index';
import buildV1Api from './router/v1';
import buildV2Api from './router/v2';
import { HttpServer } from './utils/http';
import { Websocket } from './utils/socket';

export class Server {
instanceManager: any;
app = new HttpServer();

constructor({ instanceManager }: { instanceManager: any }) {
this.instanceManager = instanceManager;

this.middlrewares();
}

start() {
const WS_V1 = new Websocket({
instanceManager: this.instanceManager,
pollRateFieldName: 'pollRate',
stateFunctionName: 'getState'
});
const WS_V2 = new Websocket({
instanceManager: this.instanceManager,
pollRateFieldName: 'pollRate',
stateFunctionName: 'getStateV2'
});
const WS_V2_KEYS = new Websocket({
instanceManager: this.instanceManager,
pollRateFieldName: 'keyOverlayPollRate',
stateFunctionName: 'getKeyOverlay'
});

buildBaseApi(this.app);
buildV1Api({
app: this.app,
websocket: WS_V1
});
buildV2Api({
app: this.app,
websocket: WS_V2,
keysWebsocket: WS_V2_KEYS
});

this.app.listen(config.serverPort, config.serverIP);
}

restart() {
this.app.server.close();
this.app.listen(config.serverPort, config.serverIP);
}

middlrewares() {
const that = this;

this.app.use((_, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept'
);
res.setHeader(
'Access-Control-Allow-Methods',
'POST, GET, PUT, DELETE, OPTIONS'
);
next();
});

this.app.use((req, _, next) => {
req.instanceManager = that.instanceManager;
next();
});
}
}

export * from './utils/http';
export * from './utils/socket';
export * from './utils/index';
export * from './http/index';
export * from './socket/index';
62 changes: 62 additions & 0 deletions packages/server/router/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { config } from '@tosu/common';
import path from 'path';

import { HttpServer, getContentType, sendJson } from '../index';
import { directoryWalker, readDirectory } from '../utils/directories';

export default function buildBaseApi(app: HttpServer) {
app.route('/json', 'GET', (req, res) => {
const osuInstances: any = Object.values(
req.instanceManager.osuInstances || {}
);
if (osuInstances.length < 1) {
res.statusCode = 500;
return sendJson(res, { error: 'not_ready' });
}

const json = osuInstances[0].getState(req.instanceManager);
sendJson(res, json);
});

app.route('/api/overlays', 'GET', (req, res) => {
const staticPath =
config.staticFolderPath ||
path.join(path.dirname(process.execPath), 'static');

readDirectory(staticPath, '/', (html: string) => {
res.writeHead(200, { 'Content-Type': getContentType('file.html') });
res.end(html);
});
});

app.route(/.*/, 'GET', (req, res) => {
const url = req.url || '/';
const folderPath =
config.staticFolderPath ||
path.join(path.dirname(process.execPath), 'static');

if (url == '/') {
return readDirectory(folderPath, url, (html: string) => {
res.writeHead(200, {
'Content-Type': getContentType('file.html')
});
res.end(html);
});
}

const extension = path.extname(url);
if (extension == '' && !url.endsWith('/')) {
res.writeHead(301, { Location: url + '/' });
return res.end();
}

const selectIndexHTML = url.endsWith('/') ? url + 'index.html' : url;
directoryWalker({
_htmlRedirect: true,
res,
baseUrl: url,
pathname: selectIndexHTML,
folderPath
});
});
}
48 changes: 48 additions & 0 deletions packages/server/router/v1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { HttpServer, Websocket, sendJson } from '../index';
import { directoryWalker } from '../utils/directories';

export default function buildV1Api({
app,
websocket
}: {
app: HttpServer;
websocket: Websocket;
}) {
app.server.on('upgrade', function (request, socket, head) {
if (request.url == '/ws') {
websocket.socket.handleUpgrade(
request,
socket,
head,
function (ws) {
websocket.socket.emit('connection', ws, request);
}
);
}
});

app.route(/\/Songs\/(?<filePath>.*)/, 'GET', (req, res) => {
const url = req.url || '/';

const osuInstances: any = Object.values(
req.instanceManager.osuInstances || {}
);
if (osuInstances.length < 1) {
res.statusCode = 500;
return sendJson(res, { error: 'not_ready' });
}

const { settings } = osuInstances[0].entities.getServices(['settings']);
if (settings.songsFolder === '') {
res.statusCode = 500;
return sendJson(res, { error: 'not_ready' });
}

directoryWalker({
res,
baseUrl: url,
pathname: req.params.filePath,
folderPath: settings.songsFolder
});
});
}
Loading

0 comments on commit ede27fc

Please sign in to comment.