Browse Source

147 koa as web server (#3)

* some commit

* use axios

* routes++
pull/1/head
Alexey Velikiy 7 years ago committed by GitHub
parent
commit
8426acdf97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 25
      server/README.md
  2. 12
      server/build/webpack.base.conf.js
  3. 17
      server/build/webpack.dev.conf.js
  4. 22
      server/package.json
  5. 36
      server/src/index.ts
  6. 41
      server/src/routes/alerts.ts
  7. 5
      server/src/routes/anomalies.ts
  8. 35
      server/src/routes/segments.ts
  9. 18
      server/src/services/alerts.ts
  10. 22
      server/src/services/notification.ts

25
server/README.md

@ -1,27 +1,4 @@
# Hastic server # Hastic server
REST server for managing data for analytics. It is a REST server based on KoaJS
Running on 8000 port.
# Build
```
npm install
npm run build
```
# Run
```
npm start
```
# Development
You should have `nodemon` module installed to run development server.
```
npm i -g nodemon
npm run dev
```

12
server/build/webpack.base.conf.js

@ -16,20 +16,18 @@ module.exports = {
}, },
context: resolve('./src'), context: resolve('./src'),
entry: './index', entry: './index',
devtool: 'inline-source-map',
output: { output: {
filename: "server.js", filename: "server.js",
path: resolve('dist') path: resolve('dist')
}, },
plugins: [ plugins: [
new webpack.optimize.OccurrenceOrderPlugin(), new webpack.optimize.OccurrenceOrderPlugin()
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development')
})
], ],
resolve: { resolve: {
extensions: [".ts", ".js"] extensions: [".ts", ".js"],
alias: {
'any-promise': 'es6-promise'
}
}, },
module: { module: {
loaders: [ loaders: [

17
server/build/webpack.dev.conf.js

@ -1,8 +1,13 @@
var base = require('./webpack.base.conf'); const base = require('./webpack.base.conf');
const webpack = require('webpack');
base.watch = true; base.watch = true;
base.externals = [ base.devtool = 'inline-source-map';
base.externals = base.externals ? base.externals : [];
base.externals.push(
function(context, request, callback) { function(context, request, callback) {
if(request[0] == '.') { if(request[0] == '.') {
callback(); callback();
@ -10,5 +15,11 @@ base.externals = [
callback(null, "require('" + request + "')"); callback(null, "require('" + request + "')");
} }
} }
] );
base.plugins = base.plugins ? base.plugins : [];
base.plugins.push(new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development')
}));
module.exports = base; module.exports = base;

22
server/package.json

@ -17,10 +17,13 @@
"url": "https://github.com/hastic/hastic-server/issues" "url": "https://github.com/hastic/hastic-server/issues"
}, },
"homepage": "https://github.com/hastic/hastic-server#readme", "homepage": "https://github.com/hastic/hastic-server#readme",
"dependencies": { "dependencies": {},
},
"devDependencies": { "devDependencies": {
"@types/express": "^4.11.1", "@types/axios": "^0.14.0",
"@types/koa": "^2.0.45",
"@types/koa-bodyparser": "^4.2.0",
"@types/koa-router": "^7.0.28",
"axios": "^0.18.0",
"babel-core": "^6.26.3", "babel-core": "^6.26.3",
"babel-loader": "^6.4.1", "babel-loader": "^6.4.1",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2", "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
@ -29,14 +32,15 @@
"babel-polyfill": "^6.26.0", "babel-polyfill": "^6.26.0",
"babel-preset-es2015": "^6.24.1", "babel-preset-es2015": "^6.24.1",
"babel-runtime": "^6.26.0", "babel-runtime": "^6.26.0",
"nodemon": "^1.17.3",
"ts-loader": "^3.5.0",
"typescript": "^2.8.3",
"webpack": "^3.5.6",
"encoding": "^0.1.12", "encoding": "^0.1.12",
"event-stream": "^3.3.4", "event-stream": "^3.3.4",
"express": "^4.16.3",
"fast-csv": "^2.4.1", "fast-csv": "^2.4.1",
"node-fetch": "^2.1.2" "koa": "^2.5.1",
"koa-bodyparser": "^4.2.1",
"koa-router": "^7.4.0",
"nodemon": "^1.17.3",
"ts-loader": "^3.5.0",
"typescript": "^2.8.3",
"webpack": "^3.5.6"
} }
} }

36
server/src/index.ts

@ -1,5 +1,6 @@
import * as express from 'express'; import * as Koa from 'koa';
import * as bodyParser from 'body-parser'; import * as Router from 'koa-router';
import { router as anomaliesRouter } from './routes/anomalies'; import { router as anomaliesRouter } from './routes/anomalies';
import { router as segmentsRouter } from './routes/segments'; import { router as segmentsRouter } from './routes/segments';
@ -9,23 +10,28 @@ import { checkDataFolders } from './services/data';
checkDataFolders(); checkDataFolders();
const app = express(); var app = new Koa();
const PORT = process.env.HASTIC_PORT || 8000; const PORT = process.env.HASTIC_PORT || 8000;
app.use(bodyParser.json()); app.use(async function(ctx) {
app.use(bodyParser.urlencoded({ extended: true })); ctx.response.header('Access-Control-Allow-Origin', '*');
ctx.response.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
app.use(function (req, res, next) { ctx.response.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
next();
}); });
app.use('/anomalies', anomaliesRouter); var anRouter = new Router();
app.use('/segments', segmentsRouter); anRouter.use('/anomalies', anomaliesRouter.routes(), anomaliesRouter.allowedMethods());
app.use('/alerts', alertsRouter);
app.use('/', (req, res) => res.send({ status: 'OK' })); var seRouter = new Router();
anRouter.use('/segments', segmentsRouter.routes(), segmentsRouter.allowedMethods());
var seRouter = new Router();
anRouter.use('/alerts', alertsRouter.routes(), alertsRouter.allowedMethods());
var rootRoute = new Router();
rootRoute.get('/', async (ctx) => {
ctx.body = { status: 'OK' };
});
app.listen(PORT, () => { app.listen(PORT, () => {
console.log(`Server is running on :${PORT}`) console.log(`Server is running on :${PORT}`)

41
server/src/routes/alerts.ts

@ -1,10 +1,12 @@
import * as express from 'express';
import { AnomalyId, getAnomalyIdByName, loadAnomalyById } from '../services/anomalyType'; import { AnomalyId, getAnomalyIdByName, loadAnomalyById } from '../services/anomalyType';
import { getAlertsAnomalies, saveAlertsAnomalies } from '../services/alerts'; import { getAlertsAnomalies, saveAlertsAnomalies } from '../services/alerts';
function getAlert(req, res) { import * as Router from 'koa-router';
try {
let anomalyId: AnomalyId = req.query.anomaly_id;
function getAlert(ctx: Router.IRouterContext) {
let anomalyId: AnomalyId = ctx.request.body.query.anomaly_id;
let anomaly = loadAnomalyById(anomalyId) let anomaly = loadAnomalyById(anomalyId)
if (anomaly == null) { if (anomaly == null) {
anomalyId = getAnomalyIdByName(anomalyId.toLowerCase()); anomalyId = getAnomalyIdByName(anomalyId.toLowerCase());
@ -14,21 +16,14 @@ function getAlert(req, res) {
let pos = alertsAnomalies.indexOf(anomalyId); let pos = alertsAnomalies.indexOf(anomalyId);
let enable: boolean = (pos !== -1); let enable: boolean = (pos !== -1);
res.status(200).send({ ctx.response.body = { enable };
enable
});
} catch(e) {
res.status(500).send({
code: 500,
message: 'Internal error'
});
}
} }
function changeAlert(req, res) { function changeAlert(ctx: Router.IRouterContext) {
try {
let anomalyId: AnomalyId = req.body.anomaly_id; let anomalyId: AnomalyId = ctx.request.body.anomaly_id;
let enable: boolean = req.body.enable; let enable: boolean = ctx.body.enable;
let anomaly = loadAnomalyById(anomalyId) let anomaly = loadAnomalyById(anomalyId)
if (anomaly == null) { if (anomaly == null) {
@ -44,18 +39,10 @@ function changeAlert(req, res) {
alertsAnomalies.splice(pos, 1); alertsAnomalies.splice(pos, 1);
saveAlertsAnomalies(alertsAnomalies); saveAlertsAnomalies(alertsAnomalies);
} }
res.status(200).send({ ctx.response.body = { status: 'Ok' };
status: 'Ok'
});
} catch(e) {
res.status(500).send({
code: 500,
message: 'Internal error'
});
}
} }
export const router = express.Router(); export const router = new Router();
router.get('/', getAlert); router.get('/', getAlert);
router.post('/', changeAlert); router.post('/', changeAlert);

5
server/src/routes/anomalies.ts

@ -1,4 +1,4 @@
import * as express from 'express'; import * as Router from 'koa-router';
import { import {
Datasource, Datasource,
@ -130,7 +130,8 @@ function deleteAnomaly(req, res) {
} }
} }
export const router = express.Router();
export var router = new Router();
router.get('/status', sendAnomalyTypeStatus); router.get('/status', sendAnomalyTypeStatus);
router.get('/', getAnomaly); router.get('/', getAnomaly);

35
server/src/routes/segments.ts

@ -1,24 +1,29 @@
import * as express from 'express'; import * as Router from 'koa-router';
import { import {
getLabeledSegments, getLabeledSegments,
insertSegments, insertSegments,
removeSegments, removeSegments,
} from '../services/segments'; } from '../services/segments';
import {
Anomaly, AnomalyId, getAnomalyIdByName, loadAnomalyById
} from '../services/anomalyType';
import { runLearning } from '../services/analytics'; import { runLearning } from '../services/analytics';
import {Anomaly, AnomalyId, getAnomalyIdByName, loadAnomalyById} from '../services/anomalyType';
async function sendSegments(req, res) { async function sendSegments(ctx: Router.IRouterContext) {
try {
let anomalyId: AnomalyId = req.query.anomaly_id; let anomalyId: AnomalyId = ctx.query.anomaly_id;
let anomaly:Anomaly = loadAnomalyById(anomalyId); let anomaly:Anomaly = loadAnomalyById(anomalyId);
if(anomaly === null) { if(anomaly === null) {
anomalyId = getAnomalyIdByName(anomalyId); anomalyId = getAnomalyIdByName(anomalyId);
} }
let lastSegmentId = req.query.last_segment; let lastSegmentId = ctx.query.last_segment;
let timeFrom = req.query.from; let timeFrom = ctx.query.from;
let timeTo = req.query.to; let timeTo = ctx.query.to;
let segments = getLabeledSegments(anomalyId); let segments = getLabeledSegments(anomalyId);
@ -36,16 +41,8 @@ async function sendSegments(req, res) {
segments = segments.filter(el => el.start < timeTo); segments = segments.filter(el => el.start < timeTo);
} }
let payload = JSON.stringify({ ctx.response.body = { segments }
segments
});
res.status(200).send(payload);
} catch(e) {
res.status(500).send({
code: 500,
message: 'Internal error'
});
}
} }
async function updateSegments(req, res) { async function updateSegments(req, res) {
@ -74,7 +71,7 @@ async function updateSegments(req, res) {
} }
} }
export const router = express.Router(); export const router = new Router();
router.get('/', sendSegments); router.get('/', sendSegments);
router.patch('/', updateSegments); router.patch('/', updateSegments);

18
server/src/services/alerts.ts

@ -1,22 +1,26 @@
import { getJsonDataSync, writeJsonDataSync } from './json'; import { getJsonDataSync, writeJsonDataSync } from './json';
import * as path from 'path';
import * as fs from 'fs';
import { AnomalyId } from './anomalyType'; import { AnomalyId } from './anomalyType';
import { ANOMALIES_PATH } from '../config';
import { runPredict } from './analytics'; import { runPredict } from './analytics';
import { sendNotification } from './notification'; import { sendNotification } from './notification';
import { getLabeledSegments } from './segments'; import { getLabeledSegments } from './segments';
import { ANOMALIES_PATH } from '../config';
import * as path from 'path';
import * as fs from 'fs';
const ALERTS_DB_PATH = path.join(ANOMALIES_PATH, `alerts_anomalies.json`);
function getAlertsAnomalies(): AnomalyId[] { function getAlertsAnomalies(): AnomalyId[] {
let filename = path.join(ANOMALIES_PATH, `alerts_anomalies.json`); if(!fs.existsSync(ALERTS_DB_PATH)) {
if(!fs.existsSync(filename)) {
saveAlertsAnomalies([]); saveAlertsAnomalies([]);
} }
return getJsonDataSync(path.join(ANOMALIES_PATH, `alerts_anomalies.json`)); return getJsonDataSync(ALERTS_DB_PATH);
} }
function saveAlertsAnomalies(anomalies: AnomalyId[]) { function saveAlertsAnomalies(anomalies: AnomalyId[]) {
return writeJsonDataSync(path.join(ANOMALIES_PATH, `alerts_anomalies.json`), anomalies); return writeJsonDataSync(ALERTS_DB_PATH, anomalies);
} }
function processAlerts(anomalyId) { function processAlerts(anomalyId) {

22
server/src/services/notification.ts

@ -1,7 +1,7 @@
import fetch from 'node-fetch'; import axios from 'axios';
import { loadAnomalyById } from './anomalyType'; import { loadAnomalyById } from './anomalyType';
function sendNotification(anomalyId, active) { export async function sendNotification(anomalyId, active) {
let anomalyName = loadAnomalyById(anomalyId).name; let anomalyName = loadAnomalyById(anomalyId).name;
console.log('Notification ' + anomalyName); console.log('Notification ' + anomalyName);
@ -16,16 +16,20 @@ function sendNotification(anomalyId, active) {
} }
let endpoint = process.env.HASTIC_ALERT_ENDPOINT; let endpoint = process.env.HASTIC_ALERT_ENDPOINT;
if(endpoint !== undefined) { if(endpoint === undefined) {
fetch(endpoint, { console.error(`Can't send alert, env HASTIC_ALERT_ENDPOINT is undefined`);
return;
}
try {
var data = await axios.post(endpoint, {
method: 'POST', method: 'POST',
body: JSON.stringify(notification) body: JSON.stringify(notification)
}) })
.then(data => console.log(data)) console.log(data);
.catch(err => console.error(`Can't send alert to ${endpoint}. Error: ${err}`)); } catch(err) {
} else { console.error(`Can't send alert to ${endpoint}. Error: ${err}`)
console.error(`Can't send alert, env HASTIC_ALERT_ENDPOINT is undefined`);
} }
} }
export { sendNotification }

Loading…
Cancel
Save