diff --git a/spikes/metrics-service/graphql/.gitignore b/spikes/metrics-service/graphql/.gitignore new file mode 100644 index 00000000..32712815 --- /dev/null +++ b/spikes/metrics-service/graphql/.gitignore @@ -0,0 +1,3 @@ +/node_modules +/npm-debug.log +.idea diff --git a/spikes/metrics-service/graphql/package.json b/spikes/metrics-service/graphql/package.json new file mode 100644 index 00000000..df8754ce --- /dev/null +++ b/spikes/metrics-service/graphql/package.json @@ -0,0 +1,16 @@ +{ + "name": "graphql", + "version": "1.0.0", + "scripts": { + "start": "node src/index.js" + }, + "main": "src/index.js", + "private": true, + "dependencies": { + "graphql": "^0.7.2", + "hapi": "^15.2.0", + "hapi-graphql": "^1.0.1", + "inert": "^4.0.2", + "require-dir": "^0.3.1" + } +} diff --git a/spikes/metrics-service/graphql/src/index.js b/spikes/metrics-service/graphql/src/index.js new file mode 100644 index 00000000..b2a6a529 --- /dev/null +++ b/spikes/metrics-service/graphql/src/index.js @@ -0,0 +1,29 @@ +const requireDir = require('require-dir'); +const plugins = require('./plugins'); +const routes = requireDir('./routes'); +const Hapi = require('hapi'); +const path = require('path'); +const fs = require('fs'); + +const server = new Hapi.Server(); + +server.connection({ + host: 'localhost', + port: 8000 +}); + +server.register(plugins, (err) => { + if (err) { + throw err; + } + + Object.keys(routes).forEach((name) => { + routes[name](server); + }); + + server.start((err) => { + server.connections.forEach((conn) => { + console.log(`started at: ${conn.info.uri}`); + }); + }); +}); diff --git a/spikes/metrics-service/graphql/src/plugins.js b/spikes/metrics-service/graphql/src/plugins.js new file mode 100644 index 00000000..5c2b7c0b --- /dev/null +++ b/spikes/metrics-service/graphql/src/plugins.js @@ -0,0 +1,15 @@ +module.exports = [ + require('inert'), { + register: require('hapi-graphql'), + options: { + query: { + pretty: true, + graphiql: true, + schema: require('./schema') + }, + route: { + path: '/graphql' + } + } + } +]; diff --git a/spikes/metrics-service/graphql/src/routes/home.js b/spikes/metrics-service/graphql/src/routes/home.js new file mode 100644 index 00000000..2dd0d7c1 --- /dev/null +++ b/spikes/metrics-service/graphql/src/routes/home.js @@ -0,0 +1,11 @@ +const path = require('path'); + +module.exports = (server) => { + server.route({ + method: 'GET', + path: '/', + handler: (request, reply) => { + reply.file(path.join(__dirname, 'index.html')); + } + }); +}; diff --git a/spikes/metrics-service/graphql/src/routes/index.html b/spikes/metrics-service/graphql/src/routes/index.html new file mode 100644 index 00000000..bf944fc5 --- /dev/null +++ b/spikes/metrics-service/graphql/src/routes/index.html @@ -0,0 +1,28 @@ + + + + + + + +
+ + + + diff --git a/spikes/metrics-service/graphql/src/routes/version.js b/spikes/metrics-service/graphql/src/routes/version.js new file mode 100644 index 00000000..987747cb --- /dev/null +++ b/spikes/metrics-service/graphql/src/routes/version.js @@ -0,0 +1,18 @@ +const Pkg = require('../../package.json'); + +const internals = { + response: { + version: Pkg.version + } +}; + +module.exports = (server) => { + server.route({ + method: 'GET', + path: '/ops/version', + config: { + description: 'Returns the version of the server', + handler: (request, reply) => reply(internals.response) + } + }); +}; diff --git a/spikes/metrics-service/graphql/src/schema.js b/spikes/metrics-service/graphql/src/schema.js new file mode 100644 index 00000000..18f83be6 --- /dev/null +++ b/spikes/metrics-service/graphql/src/schema.js @@ -0,0 +1,61 @@ +const graphql = require('graphql'); + +const { + GraphQLID, + GraphQLSchema, + GraphQLObjectType, + GraphQLString +} = graphql; + +const EventType = new GraphQLObjectType({ + name: 'EventType', + fields: { + value: { + type: GraphQLString + }, + when: { + type: GraphQLString + } + } +}); + +const EventSubscription = { + type: EventType, + args: { + container: { + type: GraphQLID + } + }, + start: function() { + console.log('start', arguments); + }, + stop: function() { + console.log('stop', arguments); + }, + resolve: function() { + console.log('resolve', arguments); + } +}; + +const subscription = new GraphQLObjectType({ + name: 'RootSubscriptionType', + fields: { + events: EventSubscription + } +}); + +module.exports = new GraphQLSchema({ + query: new GraphQLObjectType({ + name: 'Q', + fields: { + a: { type: GraphQLString }, + } + }), + mutation: new GraphQLObjectType({ + name: 'M', + fields: { + c: { type: GraphQLString }, + } + }), + subscription +}); diff --git a/spikes/metrics-service/http1/.gitignore b/spikes/metrics-service/http1/.gitignore new file mode 100644 index 00000000..32712815 --- /dev/null +++ b/spikes/metrics-service/http1/.gitignore @@ -0,0 +1,3 @@ +/node_modules +/npm-debug.log +.idea diff --git a/spikes/metrics-service/http1/package.json b/spikes/metrics-service/http1/package.json new file mode 100644 index 00000000..5a7b9cf4 --- /dev/null +++ b/spikes/metrics-service/http1/package.json @@ -0,0 +1,14 @@ +{ + "name": "http1", + "version": "1.0.0", + "scripts": { + "start": "node src/index.js" + }, + "main": "src/index.js", + "private": true, + "dependencies": { + "hapi": "^15.2.0", + "inert": "^4.0.2", + "require-dir": "^0.3.1" + } +} diff --git a/spikes/metrics-service/http1/src/index.js b/spikes/metrics-service/http1/src/index.js new file mode 100644 index 00000000..62193f1e --- /dev/null +++ b/spikes/metrics-service/http1/src/index.js @@ -0,0 +1,29 @@ +const requireDir = require('require-dir'); +const plugins = require('./plugins'); +const routes = requireDir('./routes'); +const Hapi = require('hapi'); +const path = require('path'); +const fs = require('fs'); + +const server = new Hapi.Server(); + +server.connection({ + host: 'localhost', + port: 8000 +}); + +Object.keys(routes).forEach((name) => { + routes[name](server); +}); + +server.register(plugins, (err) => { + if (err) { + throw err; + } + + server.start((err) => { + server.connections.forEach((conn) => { + console.log(`started at: ${conn.info.uri}`); + }); + }); +}); diff --git a/spikes/metrics-service/http1/src/plugins.js b/spikes/metrics-service/http1/src/plugins.js new file mode 100644 index 00000000..90649561 --- /dev/null +++ b/spikes/metrics-service/http1/src/plugins.js @@ -0,0 +1,3 @@ +module.exports = [ + require('inert') +]; \ No newline at end of file diff --git a/spikes/metrics-service/http1/src/routes/home.js b/spikes/metrics-service/http1/src/routes/home.js new file mode 100644 index 00000000..2dd0d7c1 --- /dev/null +++ b/spikes/metrics-service/http1/src/routes/home.js @@ -0,0 +1,11 @@ +const path = require('path'); + +module.exports = (server) => { + server.route({ + method: 'GET', + path: '/', + handler: (request, reply) => { + reply.file(path.join(__dirname, 'index.html')); + } + }); +}; diff --git a/spikes/metrics-service/http1/src/routes/index.html b/spikes/metrics-service/http1/src/routes/index.html new file mode 100644 index 00000000..b18c7375 --- /dev/null +++ b/spikes/metrics-service/http1/src/routes/index.html @@ -0,0 +1,16 @@ + + + + + + + + + + diff --git a/spikes/metrics-service/http1/src/routes/metrics.js b/spikes/metrics-service/http1/src/routes/metrics.js new file mode 100644 index 00000000..bc7afdd6 --- /dev/null +++ b/spikes/metrics-service/http1/src/routes/metrics.js @@ -0,0 +1,21 @@ +let messageId = 0; + +module.exports = (server) => { + server.route({ + method: 'GET', + path: '/stats', + handler: (request, reply) => { + request.raw.res.setHeader('Content-Type', 'text/event-stream'); + + const intervalId = setInterval(() => { + messageId += 1; + + const str = JSON.stringify({ + msg: messageId + }); + + request.raw.res.write(`data:${str}\n\n`); + }, 100); + } + }); +}; diff --git a/spikes/metrics-service/http1/src/routes/version.js b/spikes/metrics-service/http1/src/routes/version.js new file mode 100644 index 00000000..987747cb --- /dev/null +++ b/spikes/metrics-service/http1/src/routes/version.js @@ -0,0 +1,18 @@ +const Pkg = require('../../package.json'); + +const internals = { + response: { + version: Pkg.version + } +}; + +module.exports = (server) => { + server.route({ + method: 'GET', + path: '/ops/version', + config: { + description: 'Returns the version of the server', + handler: (request, reply) => reply(internals.response) + } + }); +}; diff --git a/spikes/metrics-service/http2/.gitignore b/spikes/metrics-service/http2/.gitignore new file mode 100644 index 00000000..32712815 --- /dev/null +++ b/spikes/metrics-service/http2/.gitignore @@ -0,0 +1,3 @@ +/node_modules +/npm-debug.log +.idea diff --git a/spikes/metrics-service/http2/cert.pem b/spikes/metrics-service/http2/cert.pem new file mode 100644 index 00000000..861d073b --- /dev/null +++ b/spikes/metrics-service/http2/cert.pem @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +MIIFtTCCA52gAwIBAgIJAK4ScT3ylJVTMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTYxMTAzMTQyNDIyWhcNMTcxMTAzMTQyNDIyWjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEA6gusYDdyFH9e6iNRT7epiZrGh7R9nwD930d1UM37cZiF5/6oKKY2rP/N +pe9qnhC+k1LV2ItEZieEun1k4c+ayFSknWtbC+2tKaX5iNVIeqTKP+f0sG+FRpZk +VMPZF4eAKze+BjFZDPoFFkvhKC9MOxEyleSR8cCzSmyhVlrgBTRWhhcSMn2BPh41 +lnUplVP/43lHUWfgs3Et5EDJihzHDjfw0jo2AZ5KtqlYxQSAMt9Z5UsvYQSRUKvD +U7YUqHMUGo5F9wZCrcYyn/KbViiiIygX0A6uHU+0ajUyf2EnR1iJsdZ5oLgG6jyk +gCwQcNstXi4JVvthXi5HPmHs+i5H1aAOnMy0t21ssARYiZUq3rSmJ2mPXzJw8SYC +SLxCEo3WxBXTDOzzne7kzNl6TC0IHTfGDa80wIa3qitK7PaLQaVrGaFy2ITwt76B +414+txdM1JINW4/P1S9jv59zkwYKaoFVGdCvnt33XtAlj7C6sManZLzgxvtHhj9i +q//GjWswea2hPTezWcpzxJRVXDzVfJGu/lfoGTnZXSVRSQ5EbKQYbVRL3zI5x0hj +MPx+w8vDV88qJgywbBZkRwLaunjAwwPdpuLUwsObc5WuwOMobe+G3ycYqHswQpjc +6Mw1158nO4Kdx8DJUq7qyRDk3g7kkvp75cbF1xU4fxNzB3VJD6sCAwEAAaOBpzCB +pDAdBgNVHQ4EFgQUyt+QUohMXTlCx4nOaozvYR3wbSowdQYDVR0jBG4wbIAUyt+Q +UohMXTlCx4nOaozvYR3wbSqhSaRHMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpT +b21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGSCCQCu +EnE98pSVUzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4ICAQBAZ4Wvcnoi +dAZ3HMBODZTw9E6NZLKgl4aVQiktkCOBOwzJKxkzCrrrr+YQXYx4rHPi85FBevt/ +NkSsm/Ux+am5iNLjMOW3kDIt1VYYQ6Wn4iPEPUeWzCeyHCOfbG3gOsjDWC1GmWaY +WIBi3Zh+7txvrzyhRdNwoS+pAZOzbljCisSDmt1an48tpojI/ZqLD+oGg0LEMuik +sBWl227KxyW9DEwLcK9K3I0zhR3NKqWYt47XYvVDq+CqiVI7+/RMwnX/gtIjjGGS +5gLdD7mS+Fjig0LtCasDqKYraNQfTAyW3afYITeU4QAKukpJXwwGil3SEP2PxG/y +GBz2x6hgQZHB+8VzeA4Zxu5SmLOetJ3yxHRi8NWbiaIn/J+wdRLMjXZ0jTvv86mE +VB9X9e0ltvCH/o/VrCOVWHuUXP0zNRawQqYB1qRZ7I7Z/Aes0TQTcQOD/RYUnsfK +Mk9XhEpp9IQerufd4e0wlUq6BBA2sN6mkgy57Zsix+LAjU15z0hDRE2xWWNmbakY +VBgUTQ8KObAMaSbzUwTildtbsDhtI6pYr8y096NjFiWqkon6R8dveZBfvv5vwoxc +h2HTw85eGHyBDcWUe7c7+D+Tp7feNVOeeWtvF7LSRnmTlzqoHdMQ5ns9DxaoUu1Y +kbIEE8WnLU0m72Vq5Jzvode8VP3tZpxyvw== +-----END CERTIFICATE----- diff --git a/spikes/metrics-service/http2/key.pem b/spikes/metrics-service/http2/key.pem new file mode 100644 index 00000000..d958f958 --- /dev/null +++ b/spikes/metrics-service/http2/key.pem @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/spikes/metrics-service/http2/package.json b/spikes/metrics-service/http2/package.json new file mode 100644 index 00000000..6f51e671 --- /dev/null +++ b/spikes/metrics-service/http2/package.json @@ -0,0 +1,17 @@ +{ + "name": "http2", + "version": "1.0.0", + "scripts": { + "start": "node src/index.js" + }, + "main": "src/index.js", + "private": true, + "dependencies": { + "bunyan": "^1.8.4", + "hapi": "^15.2.0", + "http2": "^3.3.6", + "inert": "^4.0.2", + "require-dir": "^0.3.1", + "string-to-stream": "^1.1.0" + } +} diff --git a/spikes/metrics-service/http2/src/index.js b/spikes/metrics-service/http2/src/index.js new file mode 100644 index 00000000..b6eaf5c6 --- /dev/null +++ b/spikes/metrics-service/http2/src/index.js @@ -0,0 +1,40 @@ +const http2 = require('http2'); +const requireDir = require('require-dir'); +const plugins = require('./plugins'); +const routes = requireDir('./routes'); +const Hapi = require('hapi'); +const path = require('path'); +const fs = require('fs'); + +const server = new Hapi.Server(); + +server.connection({ + listener: http2.createServer({ + key: fs.readFileSync(path.join(__dirname, '../key.pem')), + cert: fs.readFileSync(path.join(__dirname, '../cert.pem')), + log: require('bunyan').createLogger({ + name: 'server', + stream: process.stdout, + serializers: require('http2/lib/http').serializers + }) + }), + host: 'localhost', + port: 8000, + tls: true +}); + +Object.keys(routes).forEach((name) => { + routes[name](server); +}); + +server.register(plugins, (err) => { + if (err) { + throw err; + } + + server.start((err) => { + server.connections.forEach((conn) => { + console.log(`started at: ${conn.info.uri}`); + }); + }); +}); diff --git a/spikes/metrics-service/http2/src/plugins.js b/spikes/metrics-service/http2/src/plugins.js new file mode 100644 index 00000000..90649561 --- /dev/null +++ b/spikes/metrics-service/http2/src/plugins.js @@ -0,0 +1,3 @@ +module.exports = [ + require('inert') +]; \ No newline at end of file diff --git a/spikes/metrics-service/http2/src/routes/home.js b/spikes/metrics-service/http2/src/routes/home.js new file mode 100644 index 00000000..2dd0d7c1 --- /dev/null +++ b/spikes/metrics-service/http2/src/routes/home.js @@ -0,0 +1,11 @@ +const path = require('path'); + +module.exports = (server) => { + server.route({ + method: 'GET', + path: '/', + handler: (request, reply) => { + reply.file(path.join(__dirname, 'index.html')); + } + }); +}; diff --git a/spikes/metrics-service/http2/src/routes/index.html b/spikes/metrics-service/http2/src/routes/index.html new file mode 100644 index 00000000..49ec28d2 --- /dev/null +++ b/spikes/metrics-service/http2/src/routes/index.html @@ -0,0 +1,25 @@ + + + + + + + + + + diff --git a/spikes/metrics-service/http2/src/routes/metrics.js b/spikes/metrics-service/http2/src/routes/metrics.js new file mode 100644 index 00000000..4e52da94 --- /dev/null +++ b/spikes/metrics-service/http2/src/routes/metrics.js @@ -0,0 +1,38 @@ +const str = require('string-to-stream'); + +let messageId = 0; + +module.exports = (server) => { + server.route({ + method: 'GET', + path: '/stats', + handler: (request, reply) => { + request.raw.res.setHeader('Content-Type', 'text/event-stream'); + + const intervalId = setInterval(() => { + const resourcePath = `/resource/${messageId}`; + + if (!request.raw.res.push) { + clearInterval(intervalId); + return; + } + + const stream = request.raw.res.push(resourcePath, { + status: 200, + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }); + + str(JSON.stringify({ + msg: messageId + })).pipe(stream); + + request.raw.res.write(`data:${resourcePath}\n\n`); + + messageId += 1; + }, 100); + } + }); +}; diff --git a/spikes/metrics-service/http2/src/routes/version.js b/spikes/metrics-service/http2/src/routes/version.js new file mode 100644 index 00000000..987747cb --- /dev/null +++ b/spikes/metrics-service/http2/src/routes/version.js @@ -0,0 +1,18 @@ +const Pkg = require('../../package.json'); + +const internals = { + response: { + version: Pkg.version + } +}; + +module.exports = (server) => { + server.route({ + method: 'GET', + path: '/ops/version', + config: { + description: 'Returns the version of the server', + handler: (request, reply) => reply(internals.response) + } + }); +}; diff --git a/spikes/metrics-service/readme.md b/spikes/metrics-service/readme.md new file mode 100644 index 00000000..bbe8e21b --- /dev/null +++ b/spikes/metrics-service/readme.md @@ -0,0 +1,30 @@ +# metrics-service + +> A service which produces random streams of data (firehose) of interpretable metric information for various subsystems that can or will be pulled out from a container. These are currently defined in [RFD-0037](https://github.com/joyent/rfd/blob/master/rfd/0037/README.md#default-metric-keys). + +This spike's purpose was to find the best pattern to expose such metrics service with mock data. + +## http1 + + + very simple API to push data from the server to the client + + plain HTTP + - requires a connection to each container - because it's not bidirectional, we can't subscribe to more containers on-demand + +## http2 + + + very simple API to push data from the server to the client + + multiplexing + - push doesn't really help us, because it's only useful for static resources + +## graphql + + + common interface between all data resources + + filter received data + - api not finalised yet + - api not documented + +## ws (with [nes](https://github.com/hapijs/nes)) + + + strong integration with [Hapi](https://github.com/hapijs/hapi) + + allow to subscribe and unsubscribe on-demand on a single connection + - some networks might require fallback to pooling diff --git a/spikes/metrics-service/ws/.gitignore b/spikes/metrics-service/ws/.gitignore new file mode 100644 index 00000000..32712815 --- /dev/null +++ b/spikes/metrics-service/ws/.gitignore @@ -0,0 +1,3 @@ +/node_modules +/npm-debug.log +.idea diff --git a/spikes/metrics-service/ws/package.json b/spikes/metrics-service/ws/package.json new file mode 100644 index 00000000..cc9823cd --- /dev/null +++ b/spikes/metrics-service/ws/package.json @@ -0,0 +1,16 @@ +{ + "name": "ws", + "version": "1.0.0", + "scripts": { + "start": "node src/index.js" + }, + "main": "src/index.js", + "private": true, + "dependencies": { + "component-emitter": "^1.2.1", + "hapi": "^15.2.0", + "inert": "^4.0.2", + "nes": "^6.3.1", + "require-dir": "^0.3.1" + } +} diff --git a/spikes/metrics-service/ws/src/index.js b/spikes/metrics-service/ws/src/index.js new file mode 100644 index 00000000..b2a6a529 --- /dev/null +++ b/spikes/metrics-service/ws/src/index.js @@ -0,0 +1,29 @@ +const requireDir = require('require-dir'); +const plugins = require('./plugins'); +const routes = requireDir('./routes'); +const Hapi = require('hapi'); +const path = require('path'); +const fs = require('fs'); + +const server = new Hapi.Server(); + +server.connection({ + host: 'localhost', + port: 8000 +}); + +server.register(plugins, (err) => { + if (err) { + throw err; + } + + Object.keys(routes).forEach((name) => { + routes[name](server); + }); + + server.start((err) => { + server.connections.forEach((conn) => { + console.log(`started at: ${conn.info.uri}`); + }); + }); +}); diff --git a/spikes/metrics-service/ws/src/metric.js b/spikes/metrics-service/ws/src/metric.js new file mode 100644 index 00000000..de0ac268 --- /dev/null +++ b/spikes/metrics-service/ws/src/metric.js @@ -0,0 +1,30 @@ +const Emitter = require('component-emitter'); + +const cdm = {}; + +module.exports = (server) => ({ + on: (id) => { + if (cdm[id]) { + cdm[id].sockets +=1; + return; + } + + + let messageId = 0; + const interval = setInterval(() => { + server.publish(`/stats/${id}`, { + id: messageId += 1 + }); + }, 500); + + cdm[id] = { + interval, + sockets: 1 + }; + }, + off: (id) => { + if (!(cdm[id].sockets -= 1)) { + clearInterval(cdm[id].interval); + } + } +}); diff --git a/spikes/metrics-service/ws/src/plugins.js b/spikes/metrics-service/ws/src/plugins.js new file mode 100644 index 00000000..481d763d --- /dev/null +++ b/spikes/metrics-service/ws/src/plugins.js @@ -0,0 +1,4 @@ +module.exports = [ + require('inert'), + require('nes') +]; \ No newline at end of file diff --git a/spikes/metrics-service/ws/src/routes/home.js b/spikes/metrics-service/ws/src/routes/home.js new file mode 100644 index 00000000..2dd0d7c1 --- /dev/null +++ b/spikes/metrics-service/ws/src/routes/home.js @@ -0,0 +1,11 @@ +const path = require('path'); + +module.exports = (server) => { + server.route({ + method: 'GET', + path: '/', + handler: (request, reply) => { + reply.file(path.join(__dirname, 'index.html')); + } + }); +}; diff --git a/spikes/metrics-service/ws/src/routes/index.html b/spikes/metrics-service/ws/src/routes/index.html new file mode 100644 index 00000000..5aeba59c --- /dev/null +++ b/spikes/metrics-service/ws/src/routes/index.html @@ -0,0 +1,33 @@ + + + + + + + + +
+ + + + diff --git a/spikes/metrics-service/ws/src/routes/metrics.js b/spikes/metrics-service/ws/src/routes/metrics.js new file mode 100644 index 00000000..e6e1c261 --- /dev/null +++ b/spikes/metrics-service/ws/src/routes/metrics.js @@ -0,0 +1,18 @@ +const Metric = require('../metric'); + +module.exports = (server) => { + const metric = Metric(server); + + server.subscription('/stats/{id}', { + onSubscribe: (socket, path, params, next) => { + console.log('onSubscribe'); + metric.on(params.id); + next(); + }, + onUnsubscribe: (socket, path, params, next) => { + console.log('onUnsubscribe'); + metric.off(params.id); + next(); + } + }); +}; diff --git a/spikes/metrics-service/ws/src/routes/version.js b/spikes/metrics-service/ws/src/routes/version.js new file mode 100644 index 00000000..987747cb --- /dev/null +++ b/spikes/metrics-service/ws/src/routes/version.js @@ -0,0 +1,18 @@ +const Pkg = require('../../package.json'); + +const internals = { + response: { + version: Pkg.version + } +}; + +module.exports = (server) => { + server.route({ + method: 'GET', + path: '/ops/version', + config: { + description: 'Returns the version of the server', + handler: (request, reply) => reply(internals.response) + } + }); +};