diff --git a/.eslintrc.js b/.eslintrc.js index 09ff85b..46ff384 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -17,7 +17,8 @@ module.exports = { 'error', { singleQuote: true, parser: "flow", - tabWidth: 4 + tabWidth: 4, + endOfLine: 'lf' }, ], }, diff --git a/.gitignore b/.gitignore index d3002b3..e4855fa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,20 @@ +# IDE & text redactors files .idea .vscode +# Project CertSSL/ charts/ + +# Depends node_modules/ + +# Docker compose postgres-data/ -config.yaml +# Config +config.hjson .env +# Other .DS_Store \ No newline at end of file diff --git a/chart/database/server.py b/chart/database/server.py index 293ff24..a5f48de 100644 --- a/chart/database/server.py +++ b/chart/database/server.py @@ -9,7 +9,7 @@ import asyncpg from utils.load_config import load_config -config = load_config('config.yaml') +config = load_config('config.hjson') async def create_pool() -> asyncpg.pool.Pool: """ diff --git a/chart/main.py b/chart/main.py index b194c71..9fc86f2 100644 --- a/chart/main.py +++ b/chart/main.py @@ -16,7 +16,7 @@ from routes import get_chart, get_chart_period from utils.load_config import load_config app = FastAPI() -config = load_config('config.yaml') +config = load_config('config.hjson') if not os.path.exists('../charts'): os.mkdir('../charts') @@ -35,10 +35,10 @@ if __name__ == '__main__': port=3030, ssl_keyfile= config['server']['ssl']['private_key'] - if config['server']['ssl']['work'] + if config['server']['ssl']['enabled'] else None, ssl_certfile= config['server']['ssl']['cert'] - if config['server']['ssl']['work'] + if config['server']['ssl']['enabled'] else None ) diff --git a/chart/middleware/plausible_analytics.py b/chart/middleware/plausible_analytics.py index 50fa138..9da2b7c 100644 --- a/chart/middleware/plausible_analytics.py +++ b/chart/middleware/plausible_analytics.py @@ -9,7 +9,7 @@ from user_agents import parse as ua_parse from utils.load_config import load_config -config = load_config('config.yaml') +config = load_config('config.hjson') # pylint: disable=too-few-public-methods class PlausibleAnalytics: @@ -23,7 +23,7 @@ class PlausibleAnalytics: async def __call__(self, request, call_next): response = await call_next(request) - if HTTPStatus(response.status_code).is_client_error or not config['analytics']['work']: + if HTTPStatus(response.status_code).is_client_error or not config['analytics']['enabled']: return response user_agent = request.headers.get('user-agent', 'unknown') diff --git a/chart/requirements.txt b/chart/requirements.txt index 278ef87..105a064 100644 --- a/chart/requirements.txt +++ b/chart/requirements.txt @@ -1,5 +1,5 @@ matplotlib~=3.9.1 -PyYAML~=6.0.1 +hjson~=3.1.0 uvicorn~=0.29.0 fastapi[standard]~=0.115.2 starlette~=0.40.0 diff --git a/chart/utils/load_config.py b/chart/utils/load_config.py index c6f2bbd..197b974 100644 --- a/chart/utils/load_config.py +++ b/chart/utils/load_config.py @@ -1,20 +1,20 @@ -# pylint: disable=R0801 """ -This module provides a function for loading a YAML configuration file. -The function reads the file content and returns it as a Python dictionary. +Parsing and converting HJSON config to JSON """ -import yaml +import hjson +import json def load_config(file_path: str) -> dict: """ - Loads a YAML configuration file and returns its contents as a dictionary. + Load an HJSON file, convert it to a JSON string with indentation, + and return it. - This function opens the specified YAML file, parses its content, and - returns it in dictionary format, making it accessible for use in - the application. + params: file_path (str): The path to the HJSON file. - :param file_path: The path to the YAML configuration file to be loaded. - :return: A dictionary containing the parsed content of the YAML file. + returns str: The JSON string formatted with indentation. """ with open(file_path, 'r', encoding='utf-8') as file: - return yaml.safe_load(file) + hjson_data = hjson.load(file) + return json.loads( + json.dumps(hjson_data, indent=4) + ) diff --git a/collect-currency/main.js b/collect-currency/main.js index b81586a..be8722a 100644 --- a/collect-currency/main.js +++ b/collect-currency/main.js @@ -13,7 +13,7 @@ async function validateSchedule(schedule) { } async function initialize() { - await require('../shared/database/src/create_table')(); + //await require('../shared/database/src/create_table')(); } async function runTasks() { @@ -21,6 +21,7 @@ async function runTasks() { } async function main() { + console.log(config['currency']['collecting']['schedule']) await initialize(); await validateSchedule(config['currency']['collecting']['schedule']); @@ -32,8 +33,6 @@ async function main() { ); } -main().catch((err) => { - logger.error('Error in main execution:', err); -}); +main(); module.exports = { main }; diff --git a/config.example.hjson b/config.example.hjson new file mode 100644 index 0000000..4685ea6 --- /dev/null +++ b/config.example.hjson @@ -0,0 +1,57 @@ +{ + database: + { + user: DATABASE_USERNAME + password: DATABASE_PASSWORD + host: localhost + name: kekkai + port: 5432 + } + server: + { + host: 0.0.0.0 + ssl: + { + private_key: /CertSSL/privkey.pem + cert: /CertSSL/fullchain.pem + enabled: false + } + log: + { + level: info + } + } + analytics: + { + plausible_domain: plausible.io + plausible_token: TOKEN + plausiblee_api: https://plausible.io//api/event/ + enabled: false + } + currency: + { + collecting: + { + fiat: true + crypto: false + schedule: 30 8 * * * + crypto_apikey: TOKEN + } + fiat: + [ + USD + RUB + EUR + UAH + TRY + KZT + ] + crypto: + [ + ETH + TON + USDT + BTC + ] + } + } \ No newline at end of file diff --git a/config.example.yaml b/config.example.yaml deleted file mode 100644 index fef7b9b..0000000 --- a/config.example.yaml +++ /dev/null @@ -1,42 +0,0 @@ -# For more information, see the documentation -# https://kekkai-docs.redume.su/ - -database: # Postgresql database data, for connection - user: 'DATABASE_USERNAME' - password: 'DATABASE_PASSWORD' - host: 'DATABASE_HOST' - name: 'DATABASE_NAME' - port: 5432 -server: - host: '0.0.0.0' - ssl: - private_key: '/CertSSL/privkey.pem' # The path to the private SSL key file (String) - cert: '/CertSSL/fullchain.pem' # The path to the SSL certificate (String) - work: false # Enable or disable SSL support [Boolean] - log: - print: true # Enable or disable logging [Boolean] - level: 'info' # Log level (Fatal/Error/Warn/Log/Debug) [String] -analytics: - plausible_api: 'https://plausible.io/api/event/' - plausible_domain: 'PLAUSIBLE_DOMAIN' - plausible_token: 'PLAUSIBLE_TOKEN' - work: false -currency: - chart: - save: false # Enable or disable saving graphs to an image (Boolean) - collecting: - fiat: true # Turn off or turn on the collection of the fiat currency rate [Boolean] - crypto: false - schedule: '30 8 * * *' # Currency collection schedule in crontab format [String] - crypto_apikey: 'APIKEY' - fiat: # List of fiat currency to save the exchange rate [Array] - - USD - - RUB - - EUR - - UAH - - TRY - - KZT - crypto: - - ETH - - TON - - USDT diff --git a/docker-compose.yaml b/docker-compose.yaml index fa60175..36146cf 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -24,7 +24,7 @@ services: - '3000:3000' volumes: - './CertSSL:/CertSSL' - - './config.yaml:/config.yaml' + - './config.hjson:/config.hjson' depends_on: - postgres @@ -36,7 +36,7 @@ services: - '3030:3030' volumes: - './CertSSL:/CertSSL' - - './config.yaml:/config.yaml' + - './config.hjson:/config.hjson' depends_on: postgres: condition: service_healthy @@ -50,7 +50,7 @@ services: - '3050:3050' volumes: - './CertSSL:/CertSSL' - - './config.yaml:/config.yaml' + - './config.hjson:/config.hjson' docs: build: @@ -63,7 +63,7 @@ services: dockerfile: Dockerfile-collect-currency restart: unless-stopped volumes: - - './config.yaml:/config.yaml' + - './config.hjson:/config.hjson' depends_on: - postgres diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index e310848..cf37752 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -51,8 +51,8 @@ export default defineConfig({ slug: 'docs/config/config-env' }, { - label: 'Configure config.yaml', - slug: 'docs/config/config-yaml' + label: 'Configure config.hjson', + slug: 'docs/config/config-hjson' }, { label: 'Configure Nginx', diff --git a/docs/src/content/docs/docs/config/config-yaml.mdx b/docs/src/content/docs/docs/config/config-hjson.mdx similarity index 59% rename from docs/src/content/docs/docs/config/config-yaml.mdx rename to docs/src/content/docs/docs/config/config-hjson.mdx index dcd0885..fe649ce 100644 --- a/docs/src/content/docs/docs/config/config-yaml.mdx +++ b/docs/src/content/docs/docs/config/config-hjson.mdx @@ -1,66 +1,93 @@ --- -title: Configure config.yaml +title: Configure config.hjson --- import { Aside } from '@astrojs/starlight/components'; -Kekkai can be configured using the `config.yaml` file in the working directory. -`config.example.yaml`. +Kekkai can be configured using the `config.hjson` file in the working directory. +`config.example.hjson`. -```yaml +```hjson # For more information, see the documentation # https://kekkai-docs.redume.su/ -database: - user: 'DATABASE_USERNAME' - password: 'DATABASE_PASSWORD' - host: 'DATABASE_HOST' - name: 'DATABASE_NAME' - port: 5432 -server: - host: '0.0.0.0' - ssl: - private_key: '/CertSSL/privkey.pem' - cert: '/CertSSL/fullchain.pem' - work: true - log: - print: true - level: 'info' -analytics: - plausible_api: 'https://plausible.io/api/event/' - plausible_domain: 'PLAUSIBLE_DOMAIN' - plausible_token: 'PLAUSIBLE_TOKEN' - work: false -currency: - chart: - save: false - collecting: +{ + database: + { + user: DATABASE_USERNAME + password: DATABASE_PASSWORD + host: localhost + name: kekkai + port: 5432 + } + server: + { + host: 0.0.0.0 + ssl: + { + private_key: /CertSSL/privkey.pem + cert: /CertSSL/fullchain.pem + enabled: false + } + log: + { + level: info + } + } + analytics: + { + plausible_domain: plausible.io + plausible_token: TOKEN + enabled: false + } + currency: + { + collecting: + { fiat: true - schedule: '30 8 * * *' - fiat: - - USD - - RUB - - EUR - - UAH - - TRY - - KZT + crypto: false + schedule: 30 8 * * * + crypto_apikey: TOKEN + } + fiat: + [ + USD + RUB + EUR + UAH + TRY + KZT + ] + crypto: + [ + ETH + TON + USDT + BTC + ] + } + } ``` ## Database Kekkai is used as a `PostgreSQL` database. @@ -96,7 +123,7 @@ analytics: plausible_api: 'https://plausible.io/api/event/' plausible_domain: 'PLAUSIBLE_DOMAIN' plausible_token: 'PLAUSIBLE_TOKEN' - work: true + enabled: true ... ``` @@ -107,7 +134,7 @@ analytics: You can add the domain [here](https://plausible.io/sites/new?flow=provisioning). - `plausible_token`: Api token for authorization and sending requests. You can create it [here](https://plausible.io/settings/api-keys). -- `work`: Enable or disable analytics. +- `enabled`: Enable or disable analytics. ## Currency `DuckDuckGo` (fiat currency collection) and `CoinMarketCap` (cryptocurrency collection) @@ -116,25 +143,32 @@ are used to collect currency rates. ```yaml ... -currency: - chart: - save: false # Enable or disable saving graphs to an image (Boolean) - collecting: - fiat: true # Turn off or turn on the collection of the fiat currency rate [Boolean] + currency: + { + collecting: + { + fiat: true crypto: false - schedule: '30 8 * * *' # Currency collection schedule in crontab format [String] - crypto_apikey: 'APIKEY' - fiat: # List of fiat currency to save the exchange rate [Array] - - USD - - RUB - - EUR - - UAH - - TRY - - KZT - crypto: - - ETH - - TON - - USDT + schedule: 30 8 * * * + crypto_apikey: TOKEN + } + fiat: + [ + USD + RUB + EUR + UAH + TRY + KZT + ] + crypto: + [ + ETH + TON + USDT + BTC + ] + } ``` - `currency.chart.save`: Enable or disable saving graphs. diff --git a/server/main.js b/server/main.js index edc2d8a..7c72dc3 100644 --- a/server/main.js +++ b/server/main.js @@ -1,26 +1,32 @@ -const logger = require("../shared/logger/src/main.js"); -const config = require("../shared/config/src/main.js")(); +const logger = require('../shared/logger/src/main.js'); +const config = require('../shared/config/src/main.js')(); -const fs = require("fs"); -const axios = require("axios"); -const UAParser = require("ua-parser-js"); +const fs = require('fs'); +const axios = require('axios'); +const UAParser = require('ua-parser-js'); -require("../shared/database/src/create_table.js")(); +require('../shared/database/src/create_table.js')(); -const fastify = require("fastify")({ - logger: config["server"]["log"]["print"] ? logger : false, - ...(config["server"]["ssl"]["work"] +const fastify = require('fastify')({ + logger: config['server']['log']['level'] !== 'none' ? logger : false, + ...(config['server']['ssl']['enabled'] ? { - https: { - key: fs.readFileSync(config["server"]["ssl"]["private_key"], "utf8"), - cert: fs.readFileSync(config["server"]["ssl"]["cert"], "utf8"), - }, - } + https: { + key: fs.readFileSync( + config['server']['ssl']['private_key'], + 'utf8', + ), + cert: fs.readFileSync( + config['server']['ssl']['cert'], + 'utf8', + ), + }, + } : false), }); -const getRateRoute = require("./routes/getRate.js"); -const getMetadata = require("./routes/metadata.js"); +const getRateRoute = require('./routes/getRate.js'); +const getMetadata = require('./routes/metadata.js'); fastify.register(getRateRoute); fastify.register(getMetadata); @@ -28,69 +34,81 @@ fastify.register(getMetadata); fastify.setNotFoundHandler(function (res, reply) { return reply.status(404).send({ status: 404, - message: "Page not found!", - documentation: "https://kekkai-docs.redume.su/", + message: 'Page not found!', + documentation: 'https://kekkai-docs.redume.su/', }); }); -fastify.addHook("onResponse", async (request, reply) => { - const routePart = request.raw.url.split("/"); +fastify.addHook('onResponse', async (request, reply) => { + const routePart = request.raw.url.split('/'); const routePartFiltered = routePart - .filter((part) => part !== "") + .filter((part) => part !== '') .map((part) => `${part}/`); - routePartFiltered.unshift("/"); + routePartFiltered.unshift('/'); - if (!config?.["analytics"]["work"] ? config?.["analytics"]["work"] : false) + if (!config?.['analytics']['work'] ? config?.['analytics']['work'] : false) return; else if (!fastify.printRoutes().includes(routePartFiltered.at(-1))) return; - const userAgent = request.headers["user-agent"]; + const userAgent = request.headers['user-agent']; const parser = new UAParser(userAgent); const browser = parser.getBrowser(); const os = parser.getOS(); const formattedOS = - os.name && os.version ? `${os.name} ${os.version}` : "N/A"; + os.name && os.version ? `${os.name} ${os.version}` : 'N/A'; const formattedBrowser = browser.name && browser.version ? `${browser.name} ${browser.version}` - : "N/A"; + : 'N/A'; const event = { - domain: config["analytics"]["plausible_domain"], + domain: config['analytics']['plausible_domain'], name: request.routeOptions.url ? request.routeOptions.url - : "404 - Not Found", + : '404 - Not Found', url: request.raw.url, props: { method: request.method, statusCode: reply.statusCode, browser: formattedBrowser, os: formattedOS, - source: request.headers["referer"] - ? request.headers["referer"] - : "direct", + source: request.headers['referer'] + ? request.headers['referer'] + : 'direct', }, }; try { - await axios.post(config["analytics"]["plausible_api"], event, { +<<<<<<< HEAD + await axios.post( + `https://${config['analytics']['plausible_domain']}/api/event/`, + event, + { + headers: { + Authorization: `Bearer ${config['analytics']['plausible_token']}`, + 'Content-Type': 'application/json', + 'User-Agent': userAgent, + }, +======= + await axios.post(config['analytics']['plausible_api'], event, { headers: { - Authorization: `Bearer ${config["analytics"]["plausible_token"]}`, - "Content-Type": "application/json", - "User-Agent": userAgent, + Authorization: `Bearer ${config['analytics']['plausible_token']}`, + 'Content-Type': 'application/json', + 'User-Agent': userAgent, +>>>>>>> parent of da7134f (chore(server): Changed the name of the keys. Made it easier to change the domain) }, }); } catch (error) { - fastify.log.error("Error sending event to Plausible:", error.message); + fastify.log.error('Error sending event to Plausible:', error.message); } }); fastify.listen( { port: 3000, - host: config["server"]["host"] ? config["server"]["host"] : "localhost", + host: config['server']['host'] ? config['server']['host'] : 'localhost', }, (err) => { if (err) { diff --git a/shared/config/package-lock.json b/shared/config/package-lock.json index 6f0d56d..5e649ba 100644 --- a/shared/config/package-lock.json +++ b/shared/config/package-lock.json @@ -9,19 +9,16 @@ "version": "1.0.0", "license": "GPL-3.0-or-later", "dependencies": { - "yaml": "^2.5.0" + "hjson": "^3.2.2" } }, - "node_modules/yaml": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", - "integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==", - "license": "ISC", + "node_modules/hjson": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/hjson/-/hjson-3.2.2.tgz", + "integrity": "sha512-MkUeB0cTIlppeSsndgESkfFD21T2nXPRaBStLtf3cAYA2bVEFdXlodZB0TukwZiobPD1Ksax5DK4RTZeaXCI3Q==", + "license": "MIT", "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14" + "hjson": "bin/hjson" } } } diff --git a/shared/config/package.json b/shared/config/package.json index 00b3ddd..e196982 100644 --- a/shared/config/package.json +++ b/shared/config/package.json @@ -17,6 +17,6 @@ "homepage": "https://github.com/Redume/Kekkai#readme", "description": "Config management service", "dependencies": { - "yaml": "^2.5.0" + "hjson": "^3.2.2" } } diff --git a/shared/config/src/main.js b/shared/config/src/main.js index 97b7b20..d0108d8 100644 --- a/shared/config/src/main.js +++ b/shared/config/src/main.js @@ -1,10 +1,10 @@ const fs = require('fs'); -const yaml = require('yaml'); +const hjson = require('hjson'); const config = () => { - if (!fs.existsSync('../config.yaml')) return; + if (!fs.existsSync('../config.hjson')) throw new Error('Config not found'); - return yaml.parse(fs.readFileSync('../config.yaml', 'utf-8')); + return hjson.parse(fs.readFileSync('../config.hjson', 'utf-8')); }; module.exports = config; diff --git a/web/main.js b/web/main.js index 86a2f43..5d27e2f 100644 --- a/web/main.js +++ b/web/main.js @@ -1,18 +1,24 @@ -const logger = require("../shared/logger"); -const config = require("../shared/config/src/main.js")(); +const logger = require('../shared/logger'); +const config = require('../shared/config/src/main.js')(); -const fs = require("fs"); -const path = require("node:path"); +const fs = require('fs'); +const path = require('node:path'); -const fastify = require("fastify")({ - logger: config["server"]["log"]["print"] ? logger : false, - ...(config["server"]["ssl"]["work"] +const fastify = require('fastify')({ + logger: config['server']['log']['level'] !== 'none' ? logger : false, + ...(config['server']['ssl']['enabled'] ? { - https: { - key: fs.readFileSync(config["server"]["ssl"]["private_key"], "utf8"), - cert: fs.readFileSync(config["server"]["ssl"]["cert"], "utf8"), - }, - } + https: { + key: fs.readFileSync( + config['server']['ssl']['private_key'], + 'utf8', + ), + cert: fs.readFileSync( + config['server']['ssl']['cert'], + 'utf8', + ), + }, + } : false), }); @@ -23,11 +29,10 @@ fastify.register(require('@fastify/static'), { fastify.register(require('./routes/home.js')); - fastify.listen( { port: 3050, - host: config["server"]["host"] ? config["server"]["host"] : "localhost", + host: config['server']['host'] ? config['server']['host'] : 'localhost', }, (err) => { if (err) {