Browse Source

147 koa as web server (#3)

* some commit

* use axios

* routes++
pull/1/head
Alexey Velikiy 6 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. 57
      server/src/routes/alerts.ts
  7. 5
      server/src/routes/anomalies.ts
  8. 67
      server/src/routes/segments.ts
  9. 20
      server/src/services/alerts.ts
  10. 22
      server/src/services/notification.ts

25
server/README.md

@ -1,27 +1,4 @@
# 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'),
entry: './index',
devtool: 'inline-source-map',
output: {
filename: "server.js",
path: resolve('dist')
},
plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development')
})
new webpack.optimize.OccurrenceOrderPlugin()
],
resolve: {
extensions: [".ts", ".js"]
extensions: [".ts", ".js"],
alias: {
'any-promise': 'es6-promise'
}
},
module: {
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.externals = [
base.devtool = 'inline-source-map';
base.externals = base.externals ? base.externals : [];
base.externals.push(
function(context, request, callback) {
if(request[0] == '.') {
callback();
@ -10,5 +15,11 @@ base.externals = [
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;

22
server/package.json

@ -17,10 +17,13 @@
"url": "https://github.com/hastic/hastic-server/issues"
},
"homepage": "https://github.com/hastic/hastic-server#readme",
"dependencies": {
},
"dependencies": {},
"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-loader": "^6.4.1",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
@ -29,14 +32,15 @@
"babel-polyfill": "^6.26.0",
"babel-preset-es2015": "^6.24.1",
"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",
"event-stream": "^3.3.4",
"express": "^4.16.3",
"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 bodyParser from 'body-parser';
import * as Koa from 'koa';
import * as Router from 'koa-router';
import { router as anomaliesRouter } from './routes/anomalies';
import { router as segmentsRouter } from './routes/segments';
@ -9,23 +10,28 @@ import { checkDataFolders } from './services/data';
checkDataFolders();
const app = express();
var app = new Koa();
const PORT = process.env.HASTIC_PORT || 8000;
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(function (req, res, next) {
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(async function(ctx) {
ctx.response.header('Access-Control-Allow-Origin', '*');
ctx.response.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
ctx.response.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
});
app.use('/anomalies', anomaliesRouter);
app.use('/segments', segmentsRouter);
app.use('/alerts', alertsRouter);
app.use('/', (req, res) => res.send({ status: 'OK' }));
var anRouter = new Router();
anRouter.use('/anomalies', anomaliesRouter.routes(), anomaliesRouter.allowedMethods());
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, () => {
console.log(`Server is running on :${PORT}`)

57
server/src/routes/alerts.ts

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

67
server/src/routes/segments.ts

@ -1,51 +1,48 @@
import * as express from 'express';
import * as Router from 'koa-router';
import {
getLabeledSegments,
insertSegments,
removeSegments,
} from '../services/segments';
import {runLearning} from '../services/analytics';
import {Anomaly, AnomalyId, getAnomalyIdByName, loadAnomalyById} from '../services/anomalyType';
import {
Anomaly, AnomalyId, getAnomalyIdByName, loadAnomalyById
} from '../services/anomalyType';
async function sendSegments(req, res) {
try {
let anomalyId: AnomalyId = req.query.anomaly_id;
let anomaly:Anomaly = loadAnomalyById(anomalyId);
if(anomaly === null) {
anomalyId = getAnomalyIdByName(anomalyId);
}
import { runLearning } from '../services/analytics';
let lastSegmentId = req.query.last_segment;
let timeFrom = req.query.from;
let timeTo = req.query.to;
let segments = getLabeledSegments(anomalyId);
async function sendSegments(ctx: Router.IRouterContext) {
// Id filtering
if(lastSegmentId !== undefined) {
segments = segments.filter(el => el.id > lastSegmentId);
}
let anomalyId: AnomalyId = ctx.query.anomaly_id;
let anomaly:Anomaly = loadAnomalyById(anomalyId);
if(anomaly === null) {
anomalyId = getAnomalyIdByName(anomalyId);
}
// Time filtering
if(timeFrom !== undefined) {
segments = segments.filter(el => el.finish > timeFrom);
}
let lastSegmentId = ctx.query.last_segment;
let timeFrom = ctx.query.from;
let timeTo = ctx.query.to;
if(timeTo !== undefined) {
segments = segments.filter(el => el.start < timeTo);
}
let segments = getLabeledSegments(anomalyId);
let payload = JSON.stringify({
segments
});
res.status(200).send(payload);
} catch(e) {
res.status(500).send({
code: 500,
message: 'Internal error'
});
// Id filtering
if(lastSegmentId !== undefined) {
segments = segments.filter(el => el.id > lastSegmentId);
}
// Time filtering
if(timeFrom !== undefined) {
segments = segments.filter(el => el.finish > timeFrom);
}
if(timeTo !== undefined) {
segments = segments.filter(el => el.start < timeTo);
}
ctx.response.body = { segments }
}
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.patch('/', updateSegments);

20
server/src/services/alerts.ts

@ -1,22 +1,26 @@
import { getJsonDataSync, writeJsonDataSync } from './json';
import * as path from 'path';
import * as fs from 'fs';
import { AnomalyId } from './anomalyType';
import { ANOMALIES_PATH } from '../config';
import { runPredict } from './analytics';
import { sendNotification } from './notification';
import { getLabeledSegments } from './segments';
function getAlertsAnomalies() : AnomalyId[] {
let filename = path.join(ANOMALIES_PATH, `alerts_anomalies.json`);
if(!fs.existsSync(filename)) {
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[] {
if(!fs.existsSync(ALERTS_DB_PATH)) {
saveAlertsAnomalies([]);
}
return getJsonDataSync(path.join(ANOMALIES_PATH, `alerts_anomalies.json`));
return getJsonDataSync(ALERTS_DB_PATH);
}
function saveAlertsAnomalies(anomalies: AnomalyId[]) {
return writeJsonDataSync(path.join(ANOMALIES_PATH, `alerts_anomalies.json`), anomalies);
return writeJsonDataSync(ALERTS_DB_PATH, anomalies);
}
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';
function sendNotification(anomalyId, active) {
export async function sendNotification(anomalyId, active) {
let anomalyName = loadAnomalyById(anomalyId).name;
console.log('Notification ' + anomalyName);
@ -16,16 +16,20 @@ function sendNotification(anomalyId, active) {
}
let endpoint = process.env.HASTIC_ALERT_ENDPOINT;
if(endpoint !== undefined) {
fetch(endpoint, {
if(endpoint === undefined) {
console.error(`Can't send alert, env HASTIC_ALERT_ENDPOINT is undefined`);
return;
}
try {
var data = await axios.post(endpoint, {
method: 'POST',
body: JSON.stringify(notification)
})
.then(data => console.log(data))
.catch(err => console.error(`Can't send alert to ${endpoint}. Error: ${err}`));
} else {
console.error(`Can't send alert, env HASTIC_ALERT_ENDPOINT is undefined`);
console.log(data);
} catch(err) {
console.error(`Can't send alert to ${endpoint}. Error: ${err}`)
}
}
export { sendNotification }

Loading…
Cancel
Save