Browse Source

138-webhook-on-alert-instead-of-tg-bot

pull/1/head
rozetko 7 years ago
parent
commit
0a02cf245e
  1. 3259
      server/dist/server.js
  2. 16
      server/package-lock.json
  3. 2
      server/package.json
  4. 3
      server/src/index.ts
  5. 2
      server/src/services/analytics.ts
  6. 150
      server/src/services/notification.ts

3259
server/dist/server.js vendored

File diff suppressed because one or more lines are too long

16
server/package-lock.json generated

@ -1640,8 +1640,7 @@
"duplexer": { "duplexer": {
"version": "0.1.1", "version": "0.1.1",
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
"integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E="
"dev": true
}, },
"duplexer3": { "duplexer3": {
"version": "0.1.4", "version": "0.1.4",
@ -1844,7 +1843,6 @@
"version": "3.3.4", "version": "3.3.4",
"resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
"integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=",
"dev": true,
"requires": { "requires": {
"duplexer": "0.1.1", "duplexer": "0.1.1",
"from": "0.1.7", "from": "0.1.7",
@ -2169,8 +2167,7 @@
"from": { "from": {
"version": "0.1.7", "version": "0.1.7",
"resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
"integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4="
"dev": true
}, },
"fsevents": { "fsevents": {
"version": "1.2.4", "version": "1.2.4",
@ -3395,8 +3392,7 @@
"map-stream": { "map-stream": {
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
"integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ="
"dev": true
}, },
"map-visit": { "map-visit": {
"version": "1.0.0", "version": "1.0.0",
@ -3987,7 +3983,6 @@
"version": "0.0.11", "version": "0.0.11",
"resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
"integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=",
"dev": true,
"requires": { "requires": {
"through": "2.3.8" "through": "2.3.8"
} }
@ -4764,7 +4759,6 @@
"version": "0.3.3", "version": "0.3.3",
"resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",
"integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=",
"dev": true,
"requires": { "requires": {
"through": "2.3.8" "through": "2.3.8"
} }
@ -4818,7 +4812,6 @@
"version": "0.0.4", "version": "0.0.4",
"resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz",
"integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=",
"dev": true,
"requires": { "requires": {
"duplexer": "0.1.1" "duplexer": "0.1.1"
} }
@ -4962,8 +4955,7 @@
"through": { "through": {
"version": "2.3.8", "version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
"dev": true
}, },
"timed-out": { "timed-out": {
"version": "4.0.1", "version": "4.0.1",

2
server/package.json

@ -18,8 +18,10 @@
}, },
"homepage": "https://github.com/hastic/hastic-server#readme", "homepage": "https://github.com/hastic/hastic-server#readme",
"dependencies": { "dependencies": {
"event-stream": "^3.3.4",
"express": "^4.16.3", "express": "^4.16.3",
"fast-csv": "^2.4.1", "fast-csv": "^2.4.1",
"node-fetch": "^2.1.2",
"telegraf": "^3.21.0" "telegraf": "^3.21.0"
}, },
"devDependencies": { "devDependencies": {

3
server/src/index.ts

@ -4,7 +4,6 @@ import * as bodyParser from 'body-parser';
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';
import { router as alertsRouter } from './routes/alerts'; import { router as alertsRouter } from './routes/alerts';
import { tgBotInit } from './services/notification';
const app = express(); const app = express();
const PORT = process.env.HASTIC_PORT || 8000; const PORT = process.env.HASTIC_PORT || 8000;
@ -27,5 +26,3 @@ app.use('/', (req, res) => res.send({ status: 'OK' }));
app.listen(PORT, () => { app.listen(PORT, () => {
console.log(`Server is running on :${PORT}`) console.log(`Server is running on :${PORT}`)
}); });
tgBotInit();

2
server/src/services/analytics.ts

@ -9,7 +9,7 @@ import {
} from './anomalyType' } from './anomalyType'
import { getTarget } from './metrics'; import { getTarget } from './metrics';
import { getLabeledSegments, insertSegments, removeSegments } from './segments'; import { getLabeledSegments, insertSegments, removeSegments } from './segments';
import { split, map, mapSync } from 'event-stream' import { split, map, mapSync } from 'event-stream';
const learnWorker = spawn('python3', ['worker.py'], { cwd: ANALYTICS_PATH }) const learnWorker = spawn('python3', ['worker.py'], { cwd: ANALYTICS_PATH })
learnWorker.stdout.pipe(split()) learnWorker.stdout.pipe(split())

150
server/src/services/notification.ts

@ -1,140 +1,30 @@
//import * as Telegraf from 'telegraf' import fetch from 'node-fetch';
import * as path from 'path'; import { loadAnomalyById } from './anomalyType';
import { DATA_PATH } from '../config';
import { getJsonDataSync, writeJsonDataSync } from './json';
import { AnomalyId } from './anomalyType';
function sendNotification(anomalyId, active) {
type SubscriberId = string; let anomalyName = loadAnomalyById(anomalyId).name;
type SubscribersMap = Map< AnomalyId, SubscriberId[] >;
type BotConfig = {
token: string,
subscriptions: SubscribersMap
};
function sendNotification(anomalyName, active) {
console.log('Notification ' + anomalyName); console.log('Notification ' + anomalyName);
if(anomalyName in botConfig.subscriptions) {
let notificationMessage;
if(active) {
notificationMessage = 'Alert! Anomaly type ' + anomalyName;
} else {
notificationMessage = 'Ok! Anomaly type ' + anomalyName;
}
for (let SubscriberId of botConfig.subscriptions[anomalyName]) {
bot.telegram.sendMessage(SubscriberId, notificationMessage);
}
}
}
function loadBotConfig() : BotConfig {
let filename = path.join(DATA_PATH, `bot_config.json`);
let jsonData;
try {
jsonData = getJsonDataSync(filename);
} catch(e) {
console.error(e.message);
jsonData = [];
}
return jsonData;
}
function saveBotConfig(botConfig: BotConfig) {
let filename = path.join(DATA_PATH, `bot_config.json`);
try {
writeJsonDataSync(filename, botConfig);
} catch(e) {
console.error(e.message);
}
}
const commandArgs = (ctx, next) => { let notification = {
try { anomaly: anomalyName,
if(ctx.updateType === 'message') { status: ''
const text = ctx.update.message.text; };
if(text !== undefined && text.startsWith('/')) { if(active) {
const match = text.match(/^\/([^\s]+)\s?(.+)?/); notification.status = 'alert';
let args = [];
let command;
if(match !== null) {
if(match[1]) {
command = match[1];
}
if(match[2]) {
args = match[2].split(' ');
}
}
ctx.state.command = {
raw: text,
command,
args,
};
}
}
return next(ctx);
} catch (e) {
}
};
function addNotification(ctx) {
console.log('addNotification')
let command = ctx.state.command;
let chatId = ctx.chat.id;
if(command.args.length > 0) {
for (let anomalyName of command.args) {
if(!(anomalyName in botConfig.subscriptions)) {
botConfig.subscriptions[anomalyName] = []
}
if(botConfig.subscriptions[anomalyName].includes(chatId)) {
return ctx.reply('You are already subscribed on alerts from anomaly ' + command.args)
} else {
botConfig.subscriptions[anomalyName].push(chatId);
saveBotConfig(botConfig);
}
}
return ctx.reply('You have been successfully subscribed on alerts from anomaly ' + command.args)
} else { } else {
return ctx.reply('You should use syntax: \/addNotification <anomaly_name>') notification.status = 'OK';
} }
}
function removeNotification(ctx) { if(process.env.ALERT_ENDPOINT !== undefined) {
let command = ctx.state.command; fetch(process.env.ALERT_ENDPOINT, {
let chatId = ctx.chat.id; method: 'POST',
if(command.args.length > 0) { body: JSON.stringify(notification)
for (let anomalyName of command.args) { })
if(anomalyName in botConfig.subscriptions) { .then(data => console.log(data))
botConfig.subscriptions[anomalyName] = botConfig.subscriptions[anomalyName].filter(el => el !== chatId); .catch(err => console.error(`Can't send alert to ${process.env.ALERT_ENDPOINT}. Error: ${err}`));
saveBotConfig(botConfig);
}
}
return ctx.reply('You have been successfully unsubscribed from alerts from ' + command.args);
} else { } else {
return ctx.reply('You should use syntax: \/removeNotification <anomaly_name>'); console.error(`Can't send alert, env ALERT_ENDPOINT is undefined`);
}
}
// const Telegraf = require('telegraf');
let botConfig: BotConfig;
let bot;
function tgBotInit() {
try {
// botConfig = loadBotConfig();
// bot = new Telegraf(botConfig.token);
// bot.use(commandArgs);
// bot.command('addNotification', addNotification);
// bot.command('removeNotification', removeNotification);
// bot.startPolling();
} catch(e) {
// TODO: handle exception
} }
} }
export { sendNotification, tgBotInit } export { sendNotification }

Loading…
Cancel
Save