From 0fa7ca78a639c0def3f824f2e70f4f69bc7035d5 Mon Sep 17 00:00:00 2001 From: velvettear Date: Fri, 22 Apr 2022 15:58:04 +0200 Subject: [PATCH] added basic rest api --- classes/Api.js | 59 ++++++++++++++++++++++++++++++++++++++ classes/ApiServer.js | 43 +++++++++++++++++++++++++++ classes/Logger.js | 24 ---------------- classes/Server.js | 6 ++-- example_config_server.json | 7 ++++- kannon.js | 6 ++++ libs/constants.js | 7 ++++- 7 files changed, 122 insertions(+), 30 deletions(-) create mode 100644 classes/Api.js create mode 100644 classes/ApiServer.js diff --git a/classes/Api.js b/classes/Api.js new file mode 100644 index 0000000..40f1ee5 --- /dev/null +++ b/classes/Api.js @@ -0,0 +1,59 @@ +const AudioServer = require("./AudioServer"); + +class Api { + + constructor() { + this.get = new Map(); + this.post = new Map(); + this.#setup(); + } + + async handleRequest(request) { + if (request === undefined) { + return this.#createRequestResult(500); + } + const fn = this.#getFunction(request.url, request.method.toLowerCase()); + if (fn === undefined) { + return this.#createRequestResult(501); + } + await fn(); + return this.#createRequestResult(); + } + + #createRequestResult(code, message) { + if (code === undefined) { + code = 200; + } + const result = { + code: code + }; + if (message !== undefined) { + result.message = message; + } + return result; + } + + #setup() { + this.#registerEndpoint(constants.API_PLAY, constants.REQUEST_METHOD_POST, () => { + new AudioServer('/mnt/kingston/public/LEFTOVER.flac'); + }); + } + + #getFunction(url, method) { + if (url === undefined || method === undefined || this[method] === undefined) { + return; + } + return this[method].get(url); + } + + #registerEndpoint(url, method, fn) { + if (url === undefined || method === undefined || fn === undefined || this[method] === undefined) { + return false; + } + this[method].set(url, fn); + return true; + } + +} + +module.exports = Api; \ No newline at end of file diff --git a/classes/ApiServer.js b/classes/ApiServer.js new file mode 100644 index 0000000..7711716 --- /dev/null +++ b/classes/ApiServer.js @@ -0,0 +1,43 @@ +const Api = require('./Api.js'); +const http = require('http'); + +class ApiServer { + + constructor() { + this.listen = config.api?.listen || "0.0.0.0"; + this.port = config.api?.port || 9000; + this.api = new Api(); + this.server = http.createServer(); + this.requestId = 0; + } + + start() { + return new Promise((resolve, reject) => { + this.server.listen(this.port, this.listen).on('listening', () => { + this.port = this.server.address().port; + logger.info('api server listening on ' + this.listen + ':' + this.port + '...'); + this.#handleRequests(); + resolve(); + }); + this.server.on('error', (err) => { + reject('an unexpected error occured: ' + err); + }); + }); + } + + #handleRequests() { + this.server.on('request', async (request, response) => { + request.timestamp = Date.now(); + request.id = this.requestId; + this.requestId++; + logger.debug('handling api request #' + request.id + ' \'' + request.url + '\'...'); + const result = await this.api.handleRequest(request); + response.writeHead(result.code); + response.end(result.message); + logger.debug('handling api request #' + request.id + '\'' + request.url + '\' took ' + (Date.now() - request.timestamp) + 'ms'); + }); + } + +} + +module.exports = ApiServer; \ No newline at end of file diff --git a/classes/Logger.js b/classes/Logger.js index 9c34972..93113d0 100644 --- a/classes/Logger.js +++ b/classes/Logger.js @@ -48,30 +48,6 @@ class Logger { this.timestamp = value || 'DD.MM.YYYY HH:mm:ss:SS'; } - // log a http request - response object - http(object) { - if (object === undefined) { - return; - } - let message = '[' + object.request.method + ':' + object.code + '] url: \'' + object.request.url + '\''; - let counter = 1; - for (let param in object.request.body) { - message += ', parameter ' + counter + ': \'' + param + '=' + object.request.body[param] + '\''; - counter++; - } - if (object.request.timestamp) { - message += ' > ' + (new Date().getTime() - object.request.timestamp) + 'ms'; - } - if (object.data) { - message += ' > data: ' + object.data; - } - if (object.code != 200) { - error(message.trim()); - return; - } - this.debug(message.trim()); - } - // prefix log with 'info' info(message) { if (this.loglevel > LOGLEVEL_INFO) { diff --git a/classes/Server.js b/classes/Server.js index fd9015f..7704833 100644 --- a/classes/Server.js +++ b/classes/Server.js @@ -1,8 +1,6 @@ -const net = require('net'); - const Client = require('./Client.js'); - const AudioServer = require('./AudioServer.js'); +const net = require('net'); class Server { @@ -18,6 +16,7 @@ class Server { this.server.listen(this.port, this.listen).on('listening', () => { this.port = this.server.address().port; logger.info('communication server listening on ' + this.listen + ':' + this.port + '...'); + resolve(); }); this.server.on('connection', (socket) => { this.#addClient(socket); @@ -44,7 +43,6 @@ class Server { #addClient(socket) { this.clients.push(new Client(socket)); - new AudioServer('/mnt/kingston/public/DOPESMOKER.flac'); } removeClient(client) { diff --git a/example_config_server.json b/example_config_server.json index f51ddb3..8adcb18 100644 --- a/example_config_server.json +++ b/example_config_server.json @@ -5,6 +5,11 @@ "port": 3000, "heartbeat": 10000 }, + "api": { + "enabled": true, + "listen": "0.0.0.0", + "port": 9000 + }, "log": { "level": "debug", "timestamp": "DD.MM.YYYY HH:mm:ss:SS" @@ -22,7 +27,7 @@ "password": "kannon" }, "audio": { - "threshold": 30, + "threshold": 10, "bufferlimit": 64 } } \ No newline at end of file diff --git a/kannon.js b/kannon.js index 6023d5a..879e2f3 100644 --- a/kannon.js +++ b/kannon.js @@ -8,6 +8,7 @@ const Database = require('./classes/Database.js'); const Queue = require('./classes/Queue.js'); const Watcher = require('./classes/Watcher.js'); const EventParser = require('./classes/EventParser'); +const ApiServer = require('./classes/ApiServer.js'); const INTERRUPTS = ['beforeExit', 'SIGINT', 'SIGTERM']; @@ -36,6 +37,11 @@ async function main() { global.server = new Server(); await global.server.start(); } + // api server + if (util.isEnabled(global.config.api)) { + global.apiserver = new ApiServer(); + global.apiserver.start(); + } // queue and watcher if (util.isEnabled(global.config.library)) { global.queue = new Queue(); diff --git a/libs/constants.js b/libs/constants.js index b00f324..42f3821 100644 --- a/libs/constants.js +++ b/libs/constants.js @@ -10,5 +10,10 @@ module.exports = { CLIENT_STATE_PLAYING: 'playing', CLIENT_STATE_PAUSED: 'paused', CLIENT_STATE_STOPPED: 'stopped', - CLIENT_STATE_ERROR: 'error' + CLIENT_STATE_ERROR: 'error', + + REQUEST_METHOD_GET: 'get', + REQUEST_METHOD_POST: 'post', + + API_PLAY: '/play' } \ No newline at end of file