diff --git a/build/node_image/Dockerfile b/build/node_image/Dockerfile index 8333339a..d26f30ef 100644 --- a/build/node_image/Dockerfile +++ b/build/node_image/Dockerfile @@ -1,4 +1,4 @@ -FROM node:carbon +FROM node:12 WORKDIR /var/www diff --git a/hawk/.env.sample b/hawk/.env.sample index 7cf99f07..3b1c7238 100644 --- a/hawk/.env.sample +++ b/hawk/.env.sample @@ -16,3 +16,5 @@ HAWK_CATCHER_TOKEN = '' # Yandex Metrika id YANDEX_METRIKA_ID= + +HAWK_MIGRATION_HOST='wss://kepler.codex.so:443/ws' \ No newline at end of file diff --git a/hawk/config/migration.js.sample b/hawk/config/migration.js.sample new file mode 100644 index 00000000..de344945 --- /dev/null +++ b/hawk/config/migration.js.sample @@ -0,0 +1,7 @@ +module.exports = { + + MAPPING: { + 'ffd76ab0-76f9-4bdc-9977-ace85182342b': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwcm9qZWN0SWQiOiI1ZGViNzYxM2YwYTFkMDJjMmM0Yjg5OTgiLCJpYXQiOjE1NzU3MTIyNzV9.jE6zLZY2Z6lFw3YGnMUp3U9wMkMBFw6rKRzLmaJrgy8', + } + +}; diff --git a/hawk/modules/websocket.js b/hawk/modules/websocket.js new file mode 100644 index 00000000..6542191b --- /dev/null +++ b/hawk/modules/websocket.js @@ -0,0 +1,64 @@ +const WebSocket = require('ws'); + +function WebSocketClient(){ + this.number = 0; // Message number + this.autoReconnectInterval = 5*1000; // ms +} + +WebSocketClient.prototype.open = function(url){ + this.url = url; + this.instance = new WebSocket(this.url); + this.instance.on('open',()=>{ + this.onopen(); + }); + this.instance.on('message',(data,flags)=>{ + this.number ++; + this.onmessage(data,flags,this.number); + }); + this.instance.on('close',(e)=>{ + switch (e.code){ + case 1000: // CLOSE_NORMAL + console.log("WebSocket: closed"); + break; + default: // Abnormal closure + this.reconnect(e); + break; + } + this.onclose(e); + }); + this.instance.on('error',(e)=>{ + switch (e.code){ + case 'ECONNREFUSED': + this.reconnect(e); + break; + default: + this.onerror(e); + break; + } + }); +}; + +WebSocketClient.prototype.send = function(data,option){ + try{ + this.instance.send(data,option); + }catch (e){ + this.instance.emit('error',e); + } +}; + +WebSocketClient.prototype.reconnect = function(e){ + console.log(`WebSocketClient: retry in ${this.autoReconnectInterval}ms`,e); + this.instance.removeAllListeners(); + var that = this; + setTimeout(function(){ + console.log("WebSocketClient: reconnecting..."); + that.open(that.url); + },this.autoReconnectInterval); +}; + +WebSocketClient.prototype.onopen = function(e){ console.log("WebSocketClient: open",arguments); }; +WebSocketClient.prototype.onmessage = function(data,flags,number){ console.log("WebSocketClient: message",arguments); }; +WebSocketClient.prototype.onerror = function(e){ console.log("WebSocketClient: error",arguments); }; +WebSocketClient.prototype.onclose = function(e){ console.log("WebSocketClient: closed",arguments); }; + +exports.WebSocketClient = WebSocketClient; \ No newline at end of file diff --git a/hawk/package.json b/hawk/package.json index 3f08a482..05b0c003 100644 --- a/hawk/package.json +++ b/hawk/package.json @@ -78,6 +78,6 @@ "uuid": "^3.1.0", "winston": "^2.3.1", "winston-daily-rotate-file": "^1.4.6", - "ws": "3.0.0" + "ws": "7.2.0" } } diff --git a/hawk/routes/catcher/client.js b/hawk/routes/catcher/client.js index a271765f..f6eee828 100644 --- a/hawk/routes/catcher/client.js +++ b/hawk/routes/catcher/client.js @@ -1,11 +1,15 @@ let events = require('../../models/events'); let notifies = require('../../models/notifies'); +let migration = require('../../config/migration'); +let { WebSocketClient } = require('../../modules/websocket'); let WebSocket = require('ws'); let md5 = require('../../modules/utils').md5; let sourceMap = require('source-map'); let stack = require('../../modules/stack'); let project = require('../../models/project'); const JSSource = require('../../models/js-source'); +const URL = require('url'); +const { Agent } = require('https'); /** * @see {@link https://github.com/ptarjan/node-cache} @@ -69,6 +73,16 @@ let receiver = new WebSocket.Server({ port: process.env.SOCKET_PORT }); +/* Send client errors to Hawk V2 */ +let senderToHawk2 = new WebSocketClient(); +senderToHawk2.open(process.env.HAWK_MIGRATION_HOST || 'wss://kepler.codex.so:443/ws'); +senderToHawk2.onopen = function(_){ + console.log("🔗 WebSocketClient connected"); +}; +senderToHawk2.onmessage = function incoming(data) { + console.log(`Got from collector: ${data}`); +}; + /** * Get info about user browser and platform * @@ -337,7 +351,7 @@ async function processMessage(projectId, message) { * @return {Promise} */ function handleMessage(message) { - logger.info('Got javascript error from ' + message.location.host); + logger.info('Got javascript error from ' + message.location.host + ' with token: ' + message.token); // load project return project.getByToken(message.token) @@ -390,6 +404,30 @@ function handleMessage(message) { time : Math.floor(message.time / 1000) }; + // If there is migration for the token, send data to Hawk V2 + if (migration.MAPPING[message.token]) { + let eventV2 = { + token: migration.MAPPING[message.token], + catcherType: 'errors/javascript', + payload: { + title: message.message, + release: null, + timestamp: Math.floor(message.time / 1000), + context: {}, + user: null, + get: URL.parse(message.location.url, { + parseQueryString: true + }).query, + backtrace: message.stack, + } + }; + + await senderToHawk2.send(JSON.stringify(eventV2)); + + } else { + console.log(`Unsupported migration for token: ${message.token}`) + } + /** * Save event */