diff --git a/server/src/config.ts b/server/src/config.ts index 4fe44d4..ef6c23f 100644 --- a/server/src/config.ts +++ b/server/src/config.ts @@ -13,7 +13,8 @@ export const DATA_PATH = path.join(__dirname, '../../data'); export const ANALYTIC_UNITS_DATABASE_PATH = path.join(DATA_PATH, 'analytic_units.db'); export const SEGMENTS_DATABASE_PATH = path.join(DATA_PATH, 'segments.db'); -export const ANALYTIC_UNIT_CACHES_DATABASE_PATCH = path.join(DATA_PATH, 'analytic_unit_caches.db'); +export const ANALYTIC_UNIT_CACHES_DATABASE_PATH = path.join(DATA_PATH, 'analytic_unit_caches.db'); +export const PANELS_DATABASE_PATH = path.join(DATA_PATH, 'panels.db'); export const HASTIC_PORT = getConfigField('HASTIC_PORT', '8000'); diff --git a/server/src/index.ts b/server/src/index.ts index e6f1580..6824af2 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -1,6 +1,6 @@ -import { router as anomaliesRouter } from './routes/analytic_units_router'; +import { router as analyticUnitsRouter } from './routes/analytic_units_router'; import { router as segmentsRouter } from './routes/segments_router'; - +import { router as panelRouter } from './routes/panel_router'; import * as AnalyticsController from './controllers/analytics_controller'; @@ -11,8 +11,6 @@ import { HASTIC_PORT, PACKAGE_VERSION, GIT_INFO, ZMQ_CONNECTION_STRING } from '. import * as Koa from 'koa'; import * as Router from 'koa-router'; import * as bodyParser from 'koa-bodyparser'; -import * as fs from 'fs'; - AnalyticsController.init(); @@ -37,8 +35,9 @@ app.use(async function(ctx, next) { var rootRouter = new Router(); -rootRouter.use('/analyticUnits', anomaliesRouter.routes(), anomaliesRouter.allowedMethods()); +rootRouter.use('/analyticUnits', analyticUnitsRouter.routes(), analyticUnitsRouter.allowedMethods()); rootRouter.use('/segments', segmentsRouter.routes(), segmentsRouter.allowedMethods()); +rootRouter.use('/panel', panelRouter.routes(), panelRouter.allowedMethods()); //rootRouter.use('/alerts', alertsRouter.routes(), alertsRouter.allowedMethods()); rootRouter.get('/', async (ctx) => { diff --git a/server/src/models/panel_model.ts b/server/src/models/panel_model.ts new file mode 100644 index 0000000..7f9a57e --- /dev/null +++ b/server/src/models/panel_model.ts @@ -0,0 +1,67 @@ +import { AnalyticUnitId } from './analytic_unit_model'; + +import { Collection, makeDBQ } from '../services/data_service'; + +let db = makeDBQ(Collection.PANELS); + + +export type PanelId = string; + +export class Panel { + constructor( + public panelUrl: string, + public analyticUnits: AnalyticUnitId[], + public id?: PanelId + ) { + if(this.panelUrl === undefined) { + throw new Error('panelUrl is undefined'); + } + } + + public toObject() { + return { + _id: this.id, + panelUrl: this.panelUrl, + analyticUnits: this.analyticUnits + }; + } + + static fromObject(obj: any): Panel { + if(obj === undefined) { + throw new Error('obj is undefined'); + } + return new Panel( + obj.panelUrl, + obj.analyticUnits, + obj._id + ); + } +} + +export type FindOneQuery = { + panelUrl: string +} + +export async function findOne(query: FindOneQuery): Promise { + let panel = await db.findOne(query); + if(panel === null) { + return null; + } + return Panel.fromObject(panel); +} + +export async function insertAnalyticUnit(panelUrl: string, analyticUnitId: AnalyticUnitId) { + const panel = await db.findOne({ panelUrl }); + + return db.updateOne({ panelUrl }, { + analyticUnits: panel.analyticUnits.concat(analyticUnitId) + }); +} + +export async function removeAnalyticUnit(panelUrl: string, analyticUnitId: AnalyticUnitId) { + const panel = await db.findOne({ panelUrl }); + + return db.updateOne({ panelUrl }, { + analyticUnits: panel.analyticUnits.filter(analyticUnit => analyticUnit !== analyticUnitId) + }); +} diff --git a/server/src/routes/panel_router.ts b/server/src/routes/panel_router.ts new file mode 100644 index 0000000..24ca42c --- /dev/null +++ b/server/src/routes/panel_router.ts @@ -0,0 +1,73 @@ +import { AnalyticUnitId } from '../models/analytic_unit_model'; +import * as Panel from '../models/panel_model'; + +import * as Router from 'koa-router'; + + +async function getAnalyticUnits(ctx: Router.IRouterContext) { + try { + let panelUrl: string = ctx.request.query.panelUrl; + if(panelUrl === undefined || panelUrl === '') { + throw new Error('panelUrl is missing'); + } + + const analyticUnits = await Panel.findOne({ panelUrl }); + + ctx.response.body = { analyticUnits }; + } catch(e) { + ctx.response.status = 500; + ctx.response.body = { + code: 500, + message: `GET /panel error: ${e.message}` + }; + } +} + +async function addAnalyticUnit(ctx: Router.IRouterContext) { + try { + let { panelUrl, analyticUnitId } = ctx.request.body as { + panelUrl: string, analyticUnitId: AnalyticUnitId + }; + + await Panel.insertAnalyticUnit(panelUrl, analyticUnitId); + + ctx.response.body = { + code: 200, + message: 'Success' + }; + } catch(e) { + ctx.response.status = 500; + ctx.response.body = { + code: 500, + message: `POST /panel error: ${e.message}` + }; + } +} + +async function deleteAnalyticUnit(ctx: Router.IRouterContext) { + try { + let { panelUrl, analyticUnitId } = ctx.request.body as { + panelUrl: string, analyticUnitId: AnalyticUnitId + }; + + // TODO: stop task when analytic unit is removed + await Panel.removeAnalyticUnit(panelUrl, analyticUnitId); + + ctx.response.body = { + code: 200, + message: 'Success' + }; + } catch(e) { + ctx.response.status = 500; + ctx.response.body = { + code: 500, + message: `DELETE /panel error: ${e.message}` + }; + } +} + +export const router = new Router(); + +router.get('/', getAnalyticUnits); +router.post('/', addAnalyticUnit); +router.delete('/', deleteAnalyticUnit); diff --git a/server/src/services/data_service.ts b/server/src/services/data_service.ts index a0faab2..b73d663 100644 --- a/server/src/services/data_service.ts +++ b/server/src/services/data_service.ts @@ -4,7 +4,7 @@ import * as nedb from 'nedb'; import * as fs from 'fs'; -export enum Collection { ANALYTIC_UNITS, SEGMENTS, ANALYTIC_UNIT_CACHES }; +export enum Collection { ANALYTIC_UNITS, SEGMENTS, ANALYTIC_UNIT_CACHES, PANELS }; /** @@ -210,4 +210,5 @@ checkDataFolders(); // TODO: it's better if models request db which we create if it`s needed db.set(Collection.ANALYTIC_UNITS, new nedb({ filename: config.ANALYTIC_UNITS_DATABASE_PATH, autoload: true })); db.set(Collection.SEGMENTS, new nedb({ filename: config.SEGMENTS_DATABASE_PATH, autoload: true })); -db.set(Collection.ANALYTIC_UNIT_CACHES, new nedb({ filename: config.ANALYTIC_UNIT_CACHES_DATABASE_PATCH, autoload: true })); +db.set(Collection.ANALYTIC_UNIT_CACHES, new nedb({ filename: config.ANALYTIC_UNIT_CACHES_DATABASE_PATH, autoload: true })); +db.set(Collection.PANELS, new nedb({ filename: config.PANELS_DATABASE_PATH, autoload: true }));