From cf070d4ce99852cf110ccbca8b0ed23515b984b7 Mon Sep 17 00:00:00 2001 From: Roman Shtylman Date: Wed, 16 May 2018 16:41:05 -0400 Subject: [PATCH] add /api/tunnels/:id/status endpoint Provides connected_sockets information for a tunnel. --- lib/Client.js | 4 ++++ lib/TunnelAgent.js | 6 ++++++ lib/TunnelAgent.test.js | 7 +++++++ package.json | 1 + server.js | 29 ++++++++++++++++++++--------- server.test.js | 24 ++++++++++++++++++++++++ yarn.lock | 29 +++++++++++++++++++++++++++-- 7 files changed, 89 insertions(+), 11 deletions(-) diff --git a/lib/Client.js b/lib/Client.js index ccb7274..16b522e 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -12,6 +12,10 @@ class Client { this.debug = Debug('lt:Client'); } + stats() { + return this.agent.stats(); + } + handleRequest(req, res) { this.debug('> %s', req.url); const opt = { diff --git a/lib/TunnelAgent.js b/lib/TunnelAgent.js index f940aa5..efc2231 100644 --- a/lib/TunnelAgent.js +++ b/lib/TunnelAgent.js @@ -39,6 +39,12 @@ class TunnelAgent extends Agent { this.closed = false; } + stats() { + return { + connectedSockets: this.connectedSockets, + }; + } + listen() { const server = this.server; if (this.started) { diff --git a/lib/TunnelAgent.test.js b/lib/TunnelAgent.test.js index 62839c0..9505f35 100644 --- a/lib/TunnelAgent.test.js +++ b/lib/TunnelAgent.test.js @@ -173,4 +173,11 @@ describe('TunnelAgent', () => { }); assert.equal(err.message, 'foo'); }); + + it('should return stats', async () => { + const agent = new TunnelAgent(); + assert.deepEqual(agent.stats(), { + connectedSockets: 0, + }); + }); }); diff --git a/package.json b/package.json index 047eb25..0693b8d 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "esm": "3.0.34", "human-readable-ids": "1.0.3", "koa": "2.5.1", + "koa-router": "7.4.0", "localenv": "0.2.2", "optimist": "0.6.1", "pump": "3.0.0", diff --git a/server.js b/server.js index fb5124b..5a53c47 100644 --- a/server.js +++ b/server.js @@ -4,6 +4,7 @@ import tldjs from 'tldjs'; import Debug from 'debug'; import http from 'http'; import { hri } from 'human-readable-ids'; +import Router from 'koa-router'; import ClientManager from './lib/ClientManager'; @@ -25,23 +26,33 @@ export default function(opt) { const schema = opt.secure ? 'https' : 'http'; const app = new Koa(); + const router = new Router(); - // api status endpoint - app.use(async (ctx, next) => { - const path = ctx.request.path; - if (path !== '/api/status') { - await next(); - return; - } - + router.get('/api/status', async (ctx, next) => { const stats = manager.stats; - ctx.body = { tunnels: stats.tunnels, mem: process.memoryUsage(), }; }); + router.get('/api/tunnels/:id/status', async (ctx, next) => { + const clientId = ctx.params.id; + const client = manager.getClient(clientId); + if (!client) { + ctx.throw(404); + return; + } + + const stats = client.stats(); + ctx.body = { + connected_sockets: stats.connectedSockets, + }; + }); + + app.use(router.routes()); + app.use(router.allowedMethods()); + // root endpoint app.use(async (ctx, next) => { const path = ctx.request.path; diff --git a/server.test.js b/server.test.js index 3f72f2d..10bf8bc 100644 --- a/server.test.js +++ b/server.test.js @@ -82,4 +82,28 @@ describe('Server', () => { wss.close(); await new Promise(resolve => server.close(resolve)); }); + + it('should support the /api/tunnels/:id/status endpoint', async () => { + const server = createServer(); + await new Promise(resolve => server.listen(resolve)); + + // no such tunnel yet + const res = await request(server).get('/api/tunnels/foobar-test/status'); + assert.equal(res.statusCode, 404); + + // request a new client called foobar-test + { + const res = await request(server).get('/foobar-test'); + } + + { + const res = await request(server).get('/api/tunnels/foobar-test/status'); + assert.equal(res.statusCode, 200); + assert.deepEqual(res.body, { + connected_sockets: 0, + }); + } + + await new Promise(resolve => server.close(resolve)); + }); }); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index eba9339..9ad744b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -348,7 +348,7 @@ http-assert@^1.1.0: deep-equal "~1.0.1" http-errors "~1.6.1" -http-errors@^1.2.8, http-errors@~1.6.1: +http-errors@^1.2.8, http-errors@^1.3.1, http-errors@~1.6.1: version "1.6.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" dependencies: @@ -416,6 +416,10 @@ is@~0.2.6: version "0.2.7" resolved "https://registry.yarnpkg.com/is/-/is-0.2.7.tgz#3b34a2c48f359972f35042849193ae7264b63562" +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -453,6 +457,17 @@ koa-is-json@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14" +koa-router@7.4.0: + version "7.4.0" + resolved "https://registry.yarnpkg.com/koa-router/-/koa-router-7.4.0.tgz#aee1f7adc02d5cb31d7d67465c9eacc825e8c5e0" + dependencies: + debug "^3.1.0" + http-errors "^1.3.1" + koa-compose "^3.0.0" + methods "^1.0.1" + path-to-regexp "^1.1.1" + urijs "^1.19.0" + koa@2.5.1: version "2.5.1" resolved "https://registry.yarnpkg.com/koa/-/koa-2.5.1.tgz#79f8b95f8d72d04fe9a58a8da5ebd6d341103f9c" @@ -615,7 +630,7 @@ meow@^3.3.0: redent "^1.0.0" trim-newlines "^1.0.0" -methods@^1.1.1, methods@~1.1.2: +methods@^1.0.1, methods@^1.1.1, methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" @@ -782,6 +797,12 @@ path-parse@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" +path-to-regexp@^1.1.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" + dependencies: + isarray "0.0.1" + path-type@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" @@ -998,6 +1019,10 @@ type-is@^1.5.5: media-typer "0.3.0" mime-types "~2.1.18" +urijs@^1.19.0: + version "1.19.1" + resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.1.tgz#5b0ff530c0cbde8386f6342235ba5ca6e995d25a" + util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"