From 6837da5aace9cb9d66c4cb5c082661a20a414149 Mon Sep 17 00:00:00 2001 From: Manuel Astudillo Date: Tue, 30 Apr 2019 00:15:07 +0200 Subject: [PATCH] feat: add support for TLS and teams --- index.js | 23 ++++++++-- lib/proxy.js | 1 - lib/socket.ts | 117 +++++++++++++++++++++++++++++++++++++------------- 3 files changed, 107 insertions(+), 34 deletions(-) delete mode 100644 lib/proxy.js diff --git a/index.js b/index.js index 1579e20..6bf7e2d 100755 --- a/index.js +++ b/index.js @@ -29,6 +29,7 @@ program "redis port [6379]", process.env.REDIS_PORT || "6379" ) + .option("--tls [tls]", false, "Activate secured TLS connection to Redis") .option( "-h, --host [host]", "redis host [localhost]", @@ -36,6 +37,8 @@ program ) .option("-d, --database [db]", "redis database [0]", "0") .option("--passwd [passwd]", "redis password", process.env.REDIS_PASSWD) + .option("-u, --uri [uri]", "redis uri", process.env.REDIS_URI) + .option("--team [team]", "specify team where to put the connection") .option( "-b, --backend [host]", "backend domain [api.taskforce.sh]", @@ -45,7 +48,7 @@ program console.info( chalk.blue( - "Taskforce Connector v" + pkg.version + " - (c) 2017-2018 Taskforce.sh Inc." + "Taskforce Connector v" + pkg.version + " - (c) 2017-2019 Taskforce.sh Inc." ) ); @@ -72,9 +75,23 @@ lastestVersion(pkgName).then(function(version) { port: program.port, host: program.host, password: program.passwd, - db: program.database + db: program.database, + uri: program.uri, + tls: program.tls + ? { + rejectUnauthorized: false, + requestCert: true, + agent: false + } + : void 0 }; const socket = require("./dist/socket"); - socket(program.name, program.backend, program.token, connection); + socket( + program.name, + program.backend, + program.token, + connection, + program.team + ); }); diff --git a/lib/proxy.js b/lib/proxy.js deleted file mode 100644 index 8b13789..0000000 --- a/lib/proxy.js +++ /dev/null @@ -1 +0,0 @@ - diff --git a/lib/socket.ts b/lib/socket.ts index d81420e..f800af0 100644 --- a/lib/socket.ts +++ b/lib/socket.ts @@ -1,23 +1,31 @@ import { WebSocketClient } from "./ws-autoreconnect"; import * as Bull from "bull"; +import * as url from "url"; +import { RedisOptions, Redis } from "ioredis"; + const Redis = require("ioredis"); const _ = require("lodash"); const chalk = require("chalk"); interface Connection { - port: number; - host: string; - password: string; + port?: number; + host?: string; + password?: string; + db?: number; + uri?: string; + tls?: object; } module.exports = ( name: string, server: string, token: string, - connection: Connection + connection: Connection, + team?: string ) => { const ws = new WebSocketClient(); + const redisOpts = redisOptsFromConnection(connection); ws.open(server, { headers: { @@ -26,6 +34,12 @@ module.exports = ( } }); + console.log( + chalk.yellow("WebSocket:") + + chalk.blue(" opening connection to ") + + chalk.gray("Taskforce.sh") + ); + const queues: { [index: string]: Bull.Queue } = {}; ws.onopen = function open() { @@ -38,7 +52,7 @@ module.exports = ( ws.onerror = function(err) { var msg; - if (err.message === "Unexpected server response (401)") { + if (err.message === "Unexpected server response: 401") { msg = "Authorization failed, please check that you are using the correct token from your account page"; } else { @@ -54,21 +68,25 @@ module.exports = ( chalk.yellow("WebSocket: ") + chalk.green("Succesfully authorized to taskforce.sh service") ); + // // Send this connection. // const queues = await getConnectionQueues(connection); console.log( - chalk.yellow("WebSocket: ") + - chalk.green("sending connection: ") + - chalk.blue(name) + `${chalk.yellow("WebSocket: ")} ${chalk.green( + "sending connection: " + )} ${chalk.blue(name)} ${ + team ? chalk.green(" for team ") + chalk.blue(team) : "" + }` ); ws.send( JSON.stringify({ res: "connection", cmd: "update", queues, - connection: name + connection: name, + team }) ); return; @@ -122,29 +140,29 @@ module.exports = ( const queueNameRegExp = new RegExp("(.*):(.*):id"); async function getConnectionQueues( - connection: object + connection: Connection ): Promise { - const redisClient = new Redis( - _.pick(connection, ["port", "host", "family", "password", "db"]), - { - retryStrategy: function(times: number) { - times = times % 8; - const delay = Math.round(Math.pow(2, times + 8)); - console.log( - chalk.yellow("WebSocket: ") + `Reconnecting in ${delay} ms` - ); - return delay; - } - } - ); + const redisClient = new Redis(redisOpts); redisClient.on("error", (err: Error) => { console.log( - chalk.yellow("WebSocket:") + chalk.red(" redis connection error "), + chalk.yellow("Redis:") + chalk.red(" redis connection error "), err.message ); }); + redisClient.on("connect", () => { + console.log( + chalk.yellow("Redis:") + chalk.green(" connected to redis server") + ); + }); + + redisClient.on("end", () => { + console.log( + chalk.yellow("Redis:") + chalk.blue(" disconnected from redis server") + ); + }); + const keys: string[] = await redisClient.keys("*:*:id"); const queues = keys.map(function(key) { var match = queueNameRegExp.exec(key); @@ -176,8 +194,8 @@ module.exports = ( toAdd.forEach(function(queue: FoundQueue) { queues[queue.name] = new Bull(queue.name, { - redis: connection, - prefix: queue.prefix + prefix: queue.prefix, + redis: redisOpts }); }); } @@ -271,14 +289,17 @@ module.exports = ( switch (data.cmd) { case "getConnection": console.log( - chalk.yellow("WebSocket: ") + - chalk.green("sending connection: ") + - chalk.blue(name) + `${chalk.yellow("WebSocket: ")} ${chalk.green( + "sending connections: " + )} ${chalk.blue(name)} ${ + team ? chalk.green(" for team ") + chalk.blue(team) : "" + }` ); respond(msg.id, { queues, - connection: name + connection: name, + team }); break; case "getQueues": @@ -302,3 +323,39 @@ module.exports = ( ws.send(response); } }; + +function redisOptsFromConnection(connection: Connection): RedisOptions { + let opts: RedisOptions = { + ..._.pick(connection, ["port", "host", "family", "password", "db", "tls"]) + }; + + if (connection.uri) { + opts = { ...opts, ...redisOptsFromUrl(connection.uri) }; + } + + opts.retryStrategy = function(times: number) { + times = times % 8; + const delay = Math.round(Math.pow(2, times + 8)); + console.log(chalk.yellow("Redis: ") + `Reconnecting in ${delay} ms`); + return delay; + }; + return opts; +} + +function redisOptsFromUrl(urlString: string) { + const redisOpts: RedisOptions = {}; + try { + const redisUrl = url.parse(urlString); + redisOpts.port = parseInt(redisUrl.port) || 6379; + redisOpts.host = redisUrl.hostname; + redisOpts.db = redisUrl.pathname + ? parseInt(redisUrl.pathname.split("/")[1]) + : 0; + if (redisUrl.auth) { + redisOpts.password = redisUrl.auth.split(":")[1]; + } + } catch (e) { + throw new Error(e.message); + } + return redisOpts; +}