const express = require('express') const mariadb = require('mariadb') const fs = require('fs'); let db_settings = JSON.parse(fs.readFileSync('resources/db_settings.json', 'utf8')); const app = express() const pool = mariadb.createPool({ host: db_settings.host, port: db_settings.port, user: db_settings.user, password: db_settings.password, database: db_settings.database, supportBigNumbers: true, }) const PORT = 80 function convert_rights(rights) { switch (rights) { case "Super-User": return 0; case "PTS-User": return 1; case "Premium-User": return 2; case "Standard-User": return 3; case "Test-User": return 4; default: throw new Error("Could not parse Rights (" + rights + ")"); } } // encapsulate db access async function queryDB(query) { let conn; let rows; try { conn = await pool.getConnection(); rows = await conn.query(query); } catch (err) { throw err; } finally { if (conn) { conn.end(); } } return rows; } async function queryDevice(device, incoming_rights) { let config_ids = await queryDB( "SELECT config_id " + "FROM api_info " + "WHERE name=\"Gerät\" AND value LIKE \"" + device + "\"" ); let meta_map = {}; for (let i = 0; i < config_ids.length; i++) { const config_id = config_ids[i].config_id; let metas = await queryDB( "SELECT name, value " + "FROM api_info " + "WHERE config_id=\"" + config_id + "\"" ); let m = {}; m["data"] = {}; for (let j = 0; j < metas.length; j++) { let value = metas[j].value; let name = metas[j].name; if (name == "Gerät") { m["Gerät"] = value; } else { let values = JSON.parse(value); for (let [key, value] of Object.entries(values)) { if (Array.isArray(value)) { for (let i = 0; i < value.length; i++) { let v = value[i]; let rights = convert_rights(v.right); if (rights < incoming_rights) { delete values[key]; break; } } } else { if (value.right === undefined) { for (let [inner_key, inner_value] of Object.entries(value)) { if (Array.isArray(inner_value)) { for (let i = 0; i < inner_value.length; i++) { let v = inner_value[i]; for (let [inner_inner_key, inner_inner_value] of Object.entries(v)) { let rights = convert_rights(inner_inner_value.right); if (rights < incoming_rights) { delete v[inner_inner_key]; } } } } else if (inner_value.right !== undefined) { let rights = convert_rights(inner_value.right); if (rights < incoming_rights) { delete value[inner_key]; } } else { for (let [inner_inner_key, inner_inner_value] of Object.entries(inner_value)) { let rights = convert_rights(inner_inner_value.right); if (rights < incoming_rights) { delete inner_value[inner_inner_key]; } } } } } else { let rights = convert_rights(value.right); if (rights < incoming_rights) { delete values[key]; } } } } let d = m["data"]; let l = Object.keys(d).length; if (l != 0) { m["data"] = { ...d, ...values }; } else { m["data"] = values; } } } meta_map[config_id] = m; } for (let config_id of Object.keys(meta_map)) { let results = await queryDB( "SELECT id " + "FROM api_results " + "WHERE config_id=\"" + config_id + "\"" ); for (let j = 0; j < results.length; j++) { let measurements = await queryDB( "SELECT name, value, rights " + "FROM api_measurements " + "WHERE result_id=\"" + results[j].id + "\"" ); m = {} for (let k = 0; k < measurements.length; k++) { let measurement = measurements[k]; let rights = measurement.rights.replace(/['"]+/g, ''); let rights_value = convert_rights(rights); if (rights_value >= incoming_rights) { m[measurement.name] = { name: measurement.name, value: measurement.value, rights: rights }; } } meta_map[config_id][results[j].id] = m; } } return meta_map; } async function calculate(elements, parameter, operation) { switch (operation) { case "average": let tmp = 0; let count = 0; for (let param of parameter) { const value = elements.find(element => element.name == param); if (value === undefined) { continue; } count += 1; tmp += value.value; } if (count == 0) { return null; } return tmp / count; case "sum": let sum = 0; for (let param of parameter) { const value = elements.find(element => element.name == param); if (value === undefined) { return null; } sum += value.value; } return sum; case "divide": const v1 = elements.find(element => element.name == parameter[0]); const v2 = elements.find(element => element.name == parameter[1]); if (v1 === undefined || v2 === undefined || v2 == 0) { return null; } return v1.value / v2.value; case "multiply": let p = 1.0; for (let param of parameter) { const value = elements.find(element => element.name == param); if (value === undefined) { return null; } p *= value.value; } return p; case "subtract": const s1 = elements.find(element => element.name == parameter[0]); const s2 = elements.find(element => element.name == parameter[1]); if (s1 === undefined || s2 === undefined) { return null; } return s1.value - s2.value; case "discard": const value = elements.find(element => element.name == parameter[0]); const res = elements.find(element => element.name == parameter[1]); if (value === undefined || res === undefined) { return null; } if (value.value !== null && !value.value) { return res.value; } else { return 0; } default: throw "unknown operation " + operation; } } async function createResultForEntry(parameters, descriptions, calculations) { let result = {}; for (let [key, data] of Object.entries(parameters)) { if (Object.keys(data).length == 0) { return {}; } if (key == "Gerät") { continue; } let elements = findAll(data); for (let [calc_key, calc_value] of Object.entries(calculations)) { let val = null; if (calc_value.const !== undefined) { val = parseFloat(calc_value.const[0]); } else { val = await calculate(elements, calc_value.source, calc_value.operation); } if (val !== null) { elements.push({ name: calc_key, value: val }); } } console.info(elements); for (let element of elements) { let key = String(element.name); let value = element.value; let description = descriptions[key]; if (description !== undefined) { if (value !== null) { result[key] = { name: description.name, value: value, description: description.description, unit: description.unit, } } } else { for (let [description_key, description] of Object.entries(descriptions)) { if (key.startsWith(description_key)) { result[key] = { name: description.name, value: value, description: description.description, unit: description.unit, } break; } } } } } return result; } async function createResultList(parameters, descriptions, calculations) { let result = []; for (let entry of Object.values(parameters)) { let entry_result = await createResultForEntry(entry, descriptions, calculations); if (Object.keys(entry_result).length != 0) { result.push(entry_result); } } return result; } function findAll(object) { let list = []; if (object === null) { return list; } if (object.name !== undefined) { if (object.value !== undefined) { list.push({ name: object.name, value: object.value }); } else { for (let [key, value] of Object.entries(object)) { list = list.concat(findAll(value)); } } } else { for (let [key, value] of Object.entries(object)) { list = list.concat(findAll(value)); } } return list; } app.get('/ddtrust/cepi/:rights', async (request, response) => { // read parameters from DB and only return accessible let deviceParameters = await queryDevice("%Cepi%", convert_rights(request.params.rights)); // read paremeter description file let descriptions = JSON.parse(fs.readFileSync('resources/variable_description.json', 'utf8')); // read parameter calculation file, let calculations = JSON.parse(fs.readFileSync('resources/variable_calculation.json', 'utf8')); // combine description information with parameters queried from DB let result = await createResultList(deviceParameters, descriptions, calculations); response.json(result) }) app.listen(PORT, () => { console.log(`Server running on port ${PORT}`) })