diff --git a/server/src/controllers/analytics_controller.ts b/server/src/controllers/analytics_controller.ts index b10887c..e00bd38 100644 --- a/server/src/controllers/analytics_controller.ts +++ b/server/src/controllers/analytics_controller.ts @@ -108,22 +108,23 @@ async function runTask(task: AnalyticsTask): Promise { }); } -async function query(analyticUnit: AnalyticUnit.AnalyticUnit, detector: AnalyticUnit.DetectorType) { - let range; - if(detector === AnalyticUnit.DetectorType.PATTERN) { - // TODO: find labeled OR deleted segments to generate timerange - const segments = await Segment.findMany(analyticUnit.id, { labeled: true }); - if(segments.length === 0) { - throw new Error('Need at least 1 labeled segment'); - } +async function query(analyticUnit: AnalyticUnit.AnalyticUnit, detector: AnalyticUnit.DetectorType, range?: any) { + if(range === undefined) { + if(detector === AnalyticUnit.DetectorType.PATTERN) { + // TODO: find labeled OR deleted segments to generate timerange + const segments = await Segment.findMany(analyticUnit.id, { labeled: true }); + if(segments.length === 0) { + throw new Error('Need at least 1 labeled segment'); + } - range = getQueryRangeForLearningBySegments(segments); - } else if(detector === AnalyticUnit.DetectorType.THRESHOLD) { - const now = Date.now(); - range = { - from: now - 5 * SECONDS_IN_MINUTE * 1000, - to: now - }; + range = getQueryRangeForLearningBySegments(segments); + } else if(detector === AnalyticUnit.DetectorType.THRESHOLD) { + const now = Date.now(); + range = { + from: now - 5 * SECONDS_IN_MINUTE * 1000, + to: now + }; + } } console.log(`query time range: from ${new Date(range.from)} to ${new Date(range.to)}`); @@ -236,7 +237,7 @@ export async function runLearning(id: AnalyticUnit.AnalyticUnitId) { } -export async function runDetect(id: AnalyticUnit.AnalyticUnitId) { +export async function runDetect(id: AnalyticUnit.AnalyticUnitId, from?: number, to?: number) { let previousLastDetectionTime: number = undefined; try { @@ -245,7 +246,11 @@ export async function runDetect(id: AnalyticUnit.AnalyticUnitId) { let analyticUnitType = unit.type; let detector = AnalyticUnit.getDetectorByType(analyticUnitType); - const data = await query(unit, detector); + let range; + if(from !== undefined && to !== undefined) { + range = { from, to }; + } + const data = await query(unit, detector, range); let oldCache = await AnalyticUnitCache.findById(id); if(oldCache !== null) { diff --git a/server/src/index.ts b/server/src/index.ts index 5618d3c..c93f436 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -2,6 +2,7 @@ import { router as analyticUnitsRouter } from './routes/analytic_units_router'; import { router as segmentsRouter } from './routes/segments_router'; import { router as thresholdRouter } from './routes/threshold_router'; import { router as dataRouter } from './routes/data_router'; +import { router as detectionStatusRouter } from './routes/detection_status_router'; import * as AnalyticsController from './controllers/analytics_controller'; @@ -57,6 +58,7 @@ async function init() { rootRouter.use('/segments', segmentsRouter.routes(), segmentsRouter.allowedMethods()); rootRouter.use('/threshold', thresholdRouter.routes(), thresholdRouter.allowedMethods()); rootRouter.use('/query', dataRouter.routes(), dataRouter.allowedMethods()); + rootRouter.use('/detectionStatus', detectionStatusRouter.routes(), detectionStatusRouter.allowedMethods()); rootRouter.get('/', async (ctx) => { const activeWebhooks = await AnalyticsController.getActiveWebhooks(); diff --git a/server/src/routes/detection_status_router.ts b/server/src/routes/detection_status_router.ts new file mode 100644 index 0000000..6d95a72 --- /dev/null +++ b/server/src/routes/detection_status_router.ts @@ -0,0 +1,74 @@ +import * as AnalyticsController from '../controllers/analytics_controller'; +import { AnalyticUnitId } from '../models/analytic_unit_model'; + +import * as Router from 'koa-router'; +import * as _ from 'lodash'; + +export enum DetectionState { + READY = 'READY', + RUNNING = 'RUNNING', + FAILED = 'FAILED' +} + +declare type DetectionStatus = { + id: AnalyticUnitId, + from: number, + to: number, + state: DetectionState +} + +declare type DetectionStatusResponce = { + timeranges: DetectionStatus[] +} + +let runnnedDetections: DetectionStatus[] = []; + +export async function getDetectionStatus(ctx: Router.IRouterContext): Promise { + let id: AnalyticUnitId = ctx.request.query.id; + if(id === undefined || id === '') { + throw new Error('analyticUnitId (id) is missing'); + } + + let from: number = +ctx.request.query.from; + if(isNaN(from) || ctx.request.query.from === '') { + throw new Error(`from is missing or corrupted (got ${ctx.request.query.from})`); + } + let to: number = +ctx.request.query.to; + if(isNaN(to) || ctx.request.query.to === '') { + throw new Error(`to is missing or corrupted (got ${ctx.request.query.to})`); + } + + const previousRun = _.find(runnnedDetections, {id, from, to}); + if(previousRun !== undefined) { + return { + timeranges: [ + previousRun + ] + } + } + + const currentRun = { + id, + from, + to, + state: DetectionState.RUNNING + }; + runnnedDetections.push(currentRun); + + AnalyticsController.runDetect(id, from, to) + .then(() => _.find(runnnedDetections, {id, from, to}).state = DetectionState.READY) + .catch(err => { + console.error(err); + _.find(runnnedDetections, {id, from, to}).state = DetectionState.FAILED; + }); + + return { + timeranges: [ + currentRun + ] + }; +} + +export const router = new Router(); + +router.get('/', getDetectionStatus);