32 |
33 |
34 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # IDE stuff
2 | .idea
3 |
4 | # Logs
5 | logs
6 | *.log
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 |
13 | # Directory for instrumented libs generated by jscoverage/JSCover
14 | lib-cov
15 |
16 | # Coverage directory used by tools like istanbul
17 | coverage
18 |
19 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
20 | .grunt
21 |
22 | # node-waf configuration
23 | .lock-wscript
24 |
25 | # Compiled binary addons (http://nodejs.org/api/addons.html)
26 | build/Release
27 |
28 | # Dependency directory
29 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
30 | node_modules
31 |
32 | # Various tools output dir:
33 | /output
34 |
35 | /test
36 | /proxies/stubs
37 | .eslintrc
38 | .eslintignore
39 | .editorconfig
40 | .gitattributes
41 | .istanbul.yml
42 | .travis.yml
43 | conf.json
44 | .gitignore
45 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014-2017 Chaos Software Ltd.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/lib/get-language-proxy.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 | const ejs = require('ejs');
6 | const _ = require('lodash');
7 |
8 | /**
9 | * Return a language proxy for the specified service instance and
10 | * @param options
11 | * @param options.serviceInstance {object} JSON-WS service instance
12 | * @param options.language {string} target language, e.g. "JavaScript" or "Python"
13 | * @param [options.localName] {string} the name of the proxy class. Defaults to "Proxy"
14 | * @returns {object} Promise
15 | */
16 | function getLanguageProxy(options) {
17 | // Try and find if one is available
18 | const proxyScript = path.resolve(__dirname, '..', 'proxies', options.language + '.ejs');
19 |
20 | return new Promise(function(resolve, reject) {
21 | fs.stat(proxyScript, function(err) {
22 | if (err) {
23 | return reject(err);
24 | }
25 |
26 | ejs.renderFile(
27 | proxyScript,
28 | {
29 | metadata: options.serviceInstance.metadata,
30 | localName: options.localName || 'Proxy',
31 | _: _,
32 | },
33 | { _with: false },
34 | function(err, html) {
35 | if (err) {
36 | return reject(err);
37 | }
38 |
39 | resolve(html);
40 | }
41 | );
42 | });
43 | });
44 | }
45 |
46 | module.exports = getLanguageProxy;
47 |
--------------------------------------------------------------------------------
/proxies/stubs/csharp/tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("tests")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("tests")]
13 | [assembly: AssemblyCopyright("Copyright © 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("8703ea69-c995-4a97-bbe3-b15e077c259a")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | [assembly: AssemblyVersion("1.0.0.0")]
35 | [assembly: AssemblyFileVersion("1.0.0.0")]
36 |
--------------------------------------------------------------------------------
/examples/adhoc/app.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // Example/test application
4 |
5 | const http = require('http');
6 | const express = require('express');
7 | const bodyParser = require('body-parser');
8 | const jsonws = require('../../index.js');
9 | const transport = jsonws.transport;
10 | const SocketIOTransport = require('../../lib/transport/socket-io-transport');
11 | const serviceApi = require('./api.js');
12 | const path = require('path');
13 |
14 | const expressApp = express();
15 | const httpServer = http.createServer(expressApp);
16 | const registry = jsonws.registry({
17 | rootPath: '/endpoint/:sessionId',
18 | httpServer,
19 | });
20 |
21 | expressApp.set('port', 3000);
22 | expressApp.use(bodyParser.json());
23 | expressApp.use(express.static(path.join(__dirname, '..', 'browser')));
24 | expressApp.use(registry.getRouter());
25 |
26 | expressApp.get('/', function(req, res) {
27 | res.send('hello world');
28 | });
29 |
30 | expressApp.get('/test', function(req, res) {
31 | res.sendFile(path.join(__dirname, '..', 'browser', 'test.html'));
32 | });
33 |
34 | httpServer.listen(expressApp.get('port'), function() {
35 | registry.addTransport(transport.HTTP);
36 | // registry.addTransport(transport.WebSocket);
37 | // see 'examples_snippets_sio.js' for client transport example to connect to this socket
38 | registry.addTransport(new SocketIOTransport(registry, '/test-api/socket.io'));
39 | registry.addService(serviceApi);
40 | console.log('Express server listening on ' + JSON.stringify(httpServer.address()));
41 | });
42 |
--------------------------------------------------------------------------------
/proxies/stubs/csharp/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("csharp")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("csharp")]
13 | [assembly: AssemblyCopyright("Copyright © 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("2df624d0-52d9-4805-a231-ca3e8494ab57")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/proxies/stubs/csharp/csharp.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 11.00
3 | # Visual Studio 2010
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "csharp", "csharp.csproj", "{E441329A-B069-4DA2-A39C-A35F5ED40C20}"
5 | EndProject
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tests", "tests\tests.csproj", "{588E2DAF-CE6B-4109-8C33-BD9632311A4C}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CB36FC62-5F0B-4708-B4D9-0DE16F8B6D01}"
9 | ProjectSection(SolutionItems) = preProject
10 | csharp.vsmdi = csharp.vsmdi
11 | Local.testsettings = Local.testsettings
12 | TraceAndTestImpact.testsettings = TraceAndTestImpact.testsettings
13 | EndProjectSection
14 | EndProject
15 | Global
16 | GlobalSection(TestCaseManagementSettings) = postSolution
17 | CategoryFile = csharp.vsmdi
18 | EndGlobalSection
19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
20 | Debug|Any CPU = Debug|Any CPU
21 | Release|Any CPU = Release|Any CPU
22 | EndGlobalSection
23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
24 | {E441329A-B069-4DA2-A39C-A35F5ED40C20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {E441329A-B069-4DA2-A39C-A35F5ED40C20}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {E441329A-B069-4DA2-A39C-A35F5ED40C20}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {E441329A-B069-4DA2-A39C-A35F5ED40C20}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {588E2DAF-CE6B-4109-8C33-BD9632311A4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {588E2DAF-CE6B-4109-8C33-BD9632311A4C}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {588E2DAF-CE6B-4109-8C33-BD9632311A4C}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {588E2DAF-CE6B-4109-8C33-BD9632311A4C}.Release|Any CPU.Build.0 = Release|Any CPU
32 | EndGlobalSection
33 | GlobalSection(SolutionProperties) = preSolution
34 | HideSolutionNode = FALSE
35 | EndGlobalSection
36 | EndGlobal
37 |
--------------------------------------------------------------------------------
/lib/get-metadata-page.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 | const ejs = require('ejs');
6 | const getFilesContent = require('./file-utils').getFilesContent;
7 |
8 | /**
9 | * Returns the html of the rendered metadata page.
10 | * @param options
11 | * @param options.isStatic {boolean} Indicates if the page should be static.
12 | * @param options.service {object} JSON-WS service instance.
13 | * @param options.root {string} Mount point of the service registry.
14 | * @returns {object} Promise
15 | */
16 | function getMetadataPage(options) {
17 | return new Promise(function(resolve, reject) {
18 | // Find out list of proxy generators
19 | fs.readdir(__dirname + '/../proxies/', (err, files) => {
20 | if (err) {
21 | return reject(err);
22 | }
23 |
24 | const proxies = files
25 | .filter(f => f.endsWith('.ejs'))
26 | .map(f => f.substr(0, f.length - 4));
27 | const images = [
28 | path.join('..', 'static', 'event.svg'),
29 | path.join('..', 'static', 'type.svg'),
30 | path.join('..', 'static', 'snippet.svg'),
31 | path.join('..', 'static', 'method.svg'),
32 | ];
33 | const jsFiles = [path.join('..', 'static', 'prettify.js')];
34 | const cssFiles = [path.join('..', 'static', 'prettify.css')];
35 | const templateData = {
36 | metadata: options.service,
37 | ejs,
38 | proxies,
39 | isStatic: options.isStatic,
40 | root: options.root,
41 | images: getFilesContent(images, 'base64'),
42 | js: getFilesContent(jsFiles),
43 | css: getFilesContent(cssFiles),
44 | };
45 |
46 | // Render the metadata template
47 | ejs.renderFile(
48 | __dirname + '/../templates/metadata.ejs',
49 | templateData,
50 | { _with: false },
51 | (err, html) => {
52 | if (err) {
53 | return reject(err);
54 | }
55 | resolve(html);
56 | }
57 | );
58 | });
59 | });
60 | }
61 |
62 | module.exports = getMetadataPage;
63 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "json-ws",
3 | "version": "3.5.1",
4 | "author": "ChaosGroup (c) 2013-2018",
5 | "description": "JSON-RPC based Web Services with automatic help and client side source creation for Node.js/Go/JavaScript/Java/.Net/Python/PHP",
6 | "keywords": [
7 | "json",
8 | "rpc",
9 | "remote procedure call",
10 | "json-ws",
11 | "json-rpc",
12 | "web service",
13 | "web socket",
14 | "socket-io",
15 | "javascript",
16 | "go",
17 | "golang"
18 | ],
19 | "publishConfig": {
20 | "registry": "https://registry.npmjs.com"
21 | },
22 | "homepage": "https://github.com/ChaosGroup/json-ws",
23 | "repository": "https://github.com/ChaosGroup/json-ws",
24 | "bugs": "https://github.com/ChaosGroup/json-ws/issues",
25 | "license": "MIT",
26 | "dependencies": {
27 | "co": "^4.5.2",
28 | "ejs": "^2.3.4",
29 | "express": "^4.13.4",
30 | "lodash": "^4.17.4",
31 | "node-uuid": "^1.4.8",
32 | "path-to-regexp": "^1.2.1",
33 | "request": "^2.67.0",
34 | "semver": "^5.1.0"
35 | },
36 | "peerDependencies": {
37 | "socket.io": "^2.1.1",
38 | "socket.io-client": "^2.1.1",
39 | "ws": "^1.0.1"
40 | },
41 | "devDependencies": {
42 | "bluebird": "^3.2.1",
43 | "body-parser": "^1.14.2",
44 | "chai": "^3.5.0",
45 | "eslint": "5.2.0",
46 | "eslint-config-prettier": "2.9.0",
47 | "eslint-plugin-eslint-plugin": "^1.4.0",
48 | "eslint-plugin-prettier": "2.6.2",
49 | "istanbul": "^0.4.2",
50 | "jsdoc": "^3.4.0",
51 | "mocha": "^3.2.0",
52 | "nodemon": "^1.11.0",
53 | "prettier": "1.13.7"
54 | },
55 | "scripts": {
56 | "test": "mocha 'test/integration/**/*.js' 'test/unit/**/*.js'",
57 | "test-unit": "mocha 'test/unit/**/*.js'",
58 | "test-integration": "mocha 'test/integration/**/*.js'",
59 | "lint": "eslint .",
60 | "jsdoc": "jsdoc . -c conf.json",
61 | "cover": "istanbul cover _mocha 'test/unit/**/*.js'",
62 | "example-app": "nodemon examples/adhoc/app.js"
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/proxies/stubs/php/test.php:
--------------------------------------------------------------------------------
1 | gt = new GeneratedTest('http://localhost:3000/endpoint/1.0');
8 | }
9 |
10 | public function testEcho() {
11 | $renderOptions = GeneratedTest::RenderOptions(array(
12 | 'renderMode' => 'RtGpuCuda',
13 | 'width' => 320,
14 | 'height' => 240
15 | ));
16 |
17 | $result = $this->gt->echo_($renderOptions);
18 |
19 | $this->assertEquals($renderOptions, $result);
20 | }
21 |
22 | public function testSum() {
23 | $result = $this->gt->sum(2, 3);
24 |
25 | $this->assertEquals(5, $result);
26 | }
27 |
28 | public function testEchoObject() {
29 | $obj = (object) array('foo' => 'bar');
30 | $result = $this->gt->echoObject($obj);
31 |
32 | $this->assertEquals($obj, $result);
33 | }
34 |
35 | public function testNs1Method1() {
36 | $result = $this->gt->ns1_method1();
37 |
38 | $this->assertEquals('test1', $result);
39 | }
40 |
41 | public function testTestDefaultArray() {
42 | $result = $this->gt->testDefaultArray(GeneratedTest::DefaultArray(array(
43 | 'property' => array(1, 2, 3)
44 | )));
45 |
46 | $this->assertEquals(NULL, $result);
47 | }
48 |
49 | public function testGetRenderOptions() {
50 | $result = $this->gt->getRenderOptions();
51 |
52 | $this->assertEquals(count($result), 3);
53 | $this->assertEquals((object) array(
54 | 'width' => 640,
55 | 'height' => 360,
56 | 'renderMode' => 'RtCpu'
57 | ), $result[0]);
58 | }
59 |
60 | public function testNs1Sub1Sub2Method1() {
61 | $this->setExpectedException('ExecutionException');
62 |
63 | $result = $this->gt->ns1_sub1_sub2_method1();
64 | }
65 |
66 | public function testOptionalArgs() {
67 | $this->gt->optionalArgs(true, 1, 2);
68 | $this->gt->optionalArgs(true, 1);
69 | $this->gt->optionalArgs(true);
70 | }
71 |
72 | public function testEchoStringAsBuffer() {
73 | $result = $this->gt->echoStringAsBuffer('abcd');
74 |
75 | $this->assertEquals('abcd', $result);
76 | }
77 |
78 | public function testGetBufferSize() {
79 | $result = $this->gt->getBufferSize('abcd');
80 |
81 | $this->assertEquals(4, $result);
82 | }
83 |
84 | public function testGetSeconds() {
85 | $result = $this->gt->getSeconds(new DateTime('2012-12-21 11:14:12'));
86 |
87 | $this->assertEquals(12, $result);
88 | }
89 |
90 | public function testGetNow() {
91 | $result = $this->gt->getNow();
92 |
93 | $this->assertInstanceOf('DateTime', $result);
94 | }
95 | }
96 |
97 | ?>
98 |
--------------------------------------------------------------------------------
/test/unit/lib/api.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Tests the API of the JSON-WS library
3 | */
4 |
5 | 'use strict';
6 |
7 | const expect = require('chai').expect;
8 | const jsonws = require('../../../index.js');
9 | const Service = jsonws.service;
10 |
11 | describe('Converters', function() {
12 | let api;
13 | let testType;
14 | const converting = function(value) {
15 | return function() {
16 | testType.convert(value);
17 | };
18 | };
19 |
20 | beforeEach(function() {
21 | api = new Service('1.0.0', 'test-api');
22 | api.type('TestType', {
23 | intField: {
24 | type: 'int',
25 | required: false,
26 | },
27 | floatField: {
28 | type: 'float',
29 | required: false,
30 | },
31 | booleanField: {
32 | type: 'boolean',
33 | required: false,
34 | },
35 | dateField: {
36 | type: 'date',
37 | required: false,
38 | },
39 | urlField: {
40 | type: 'url',
41 | required: false,
42 | },
43 | bufferField: {
44 | type: 'buffer',
45 | required: false,
46 | },
47 | errorField: {
48 | type: 'error',
49 | required: false,
50 | },
51 | });
52 |
53 | testType = api.type('TestType');
54 | });
55 |
56 | it('adds the field name for invalid integer values', function() {
57 | expect(converting({ intField: null })).to.throw(/\[TestType.intField\].*invalid integer/i);
58 | });
59 |
60 | it('adds the field name for invalid float values', function() {
61 | expect(converting({ floatField: null })).to.throw(
62 | /\[TestType.floatField\].*invalid number/i
63 | );
64 | });
65 |
66 | it('adds the field name for invalid boolean values', function() {
67 | expect(converting({ booleanField: 'INVALID_BOOLEAN' })).to.throw(
68 | /\[TestType.booleanField\].*invalid boolean/i
69 | );
70 | });
71 |
72 | it('adds the field name for invalid date values', function() {
73 | expect(converting({ dateField: { INVALID_DATE: true } })).to.throw(
74 | /\[TestType.dateField\].*invalid date/i
75 | );
76 | });
77 |
78 | it('adds the field name for invalid url values', function() {
79 | expect(converting({ urlField: 1234 })).to.throw(/\[TestType.urlField\].*invalid URL/i);
80 | });
81 |
82 | it('adds the field name for invalid buffer values', function() {
83 | expect(converting({ bufferField: null })).to.throw(
84 | /\[TestType.bufferField\].*invalid buffer/i
85 | );
86 | });
87 |
88 | it('adds the field name for invalid error values', function() {
89 | expect(converting({ bufferField: '', errorField: 42 })).to.throw(
90 | /\[TestType.errorField\].*invalid error/i
91 | );
92 | });
93 | });
94 |
--------------------------------------------------------------------------------
/lib/get-playground-page.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const ejs = require('ejs');
4 | const _ = require('lodash');
5 | const getFilesContent = require('./file-utils').getFilesContent;
6 |
7 | /**
8 | * Returns the html of the rendered metadata page.
9 | * @param options
10 | * @param options.isStatic {boolean} Indicates if the page should be static.
11 | * @param options.service {object} JSON-WS service instance.
12 | * @param options.root {string} Mount point of the service registry.
13 | * @returns {object} Promise
14 | */
15 | function getPlaygroundPage(options) {
16 | return new Promise(function(resolve, reject) {
17 | // Render viewer/experiment page
18 | const examples = [];
19 | const service = options.service;
20 | // TODO: update these loops when methodMap and snippetMap become maps:
21 | for (const method in service.methodMap) {
22 | if (service.methodMap[method].examples['JavaScript']) {
23 | examples.push(method);
24 | }
25 | }
26 | const snippets = [];
27 | for (const snippet in service.snippetMap) {
28 | if (service.snippetMap[snippet]['JavaScript']) {
29 | snippets.push(snippet);
30 | }
31 | }
32 | let code = null;
33 | let name = options.example;
34 | if (examples.indexOf(name) > -1) {
35 | code = service.methodMap[name].examples['JavaScript'];
36 | } else {
37 | name = options.snippet;
38 | if (snippets.indexOf(name) > -1) {
39 | code = service.snippetMap[name]['JavaScript'];
40 | }
41 | }
42 |
43 | let socketIoBackendTransportInstanceRegistered = false;
44 | if (options.registry && options.registry.transports) {
45 | for (const transport of options.registry.transports.values()) {
46 | if (transport.constructor.type === 'SocketIO') {
47 | socketIoBackendTransportInstanceRegistered = true;
48 | break;
49 | }
50 | }
51 | }
52 |
53 | const jsFiles = [
54 | './client/jsonws-polyfill.js',
55 | './client/transports/http.js',
56 | './client/transports/ws.js',
57 | './client/index.js',
58 | ];
59 |
60 | if (socketIoBackendTransportInstanceRegistered) {
61 | jsFiles.push(require.resolve('socket.io-client/dist/socket.io.js'));
62 | jsFiles.push('./client/transports/socket-io.js');
63 | }
64 |
65 | const templateData = {
66 | metadata: service,
67 | constructorName: _.upperFirst(_.camelCase(service.name)),
68 | ejs,
69 | code,
70 | title: `${service.name} ${service.version}`,
71 | examples,
72 | snippets,
73 | jsFiles: getFilesContent(jsFiles),
74 | };
75 |
76 | // Render the metadata template
77 | ejs.renderFile(
78 | __dirname + '/../templates/viewer.ejs',
79 | templateData,
80 | { _with: false },
81 | (err, html) => {
82 | if (err) {
83 | return reject(err);
84 | }
85 | resolve(html);
86 | }
87 | );
88 | });
89 | }
90 |
91 | module.exports = getPlaygroundPage;
92 |
--------------------------------------------------------------------------------
/lib/trace.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const url = require('url');
4 | const ServiceError = require('./error');
5 |
6 | class Trace {
7 | constructor(bunyanLogger) {
8 | this._enabled = !!bunyanLogger;
9 | this._logger = bunyanLogger;
10 | }
11 |
12 | _stringify(object) {
13 | if (!this._enabled) {
14 | return null;
15 | }
16 |
17 | return JSON.stringify(
18 | object,
19 | function(key, value) {
20 | if (value instanceof Buffer) {
21 | return '(buffer)';
22 | } else if (value instanceof Array && value.length > 1000) {
23 | return '(large array)';
24 | } else if (typeof value == 'string' && value.length > 1000) {
25 | return '(large string)';
26 | } else if (value instanceof url.Url) {
27 | return value.format();
28 | }
29 | return value;
30 | },
31 | 2
32 | );
33 | }
34 |
35 | /**
36 | * Logs the given message if the logger is enabled, using the appropriate logLevel
37 | * The default logLevel is "trace"
38 | *
39 | * @param {object} context
40 | * @param {string} message
41 | * @param {object} [logFields={}]
42 | * @param {string} [logLevel="trace"]
43 | * @private
44 | */
45 | _log(context, message, logFields = {}, logLevel = 'trace') {
46 | if (this._enabled) {
47 | this._logger[logLevel](logFields, `[JSON-WS] client :: ${message}`);
48 | }
49 | }
50 |
51 | connect(context) {
52 | this._log(context, 'connected');
53 | }
54 |
55 | disconnect(context) {
56 | this._log(context, 'disconnected');
57 | }
58 |
59 | call(context, methodInfo, args) {
60 | this._log(context, `method "${methodInfo.name}" call`, {
61 | method: methodInfo.name,
62 | args: this._stringify(args, null, 2),
63 | });
64 | }
65 |
66 | response(context, methodInfo, value) {
67 | this._log(context, `method "${methodInfo.name}" response`, {
68 | method: methodInfo.name,
69 | return: this._stringify(value, null, 2),
70 | });
71 | }
72 |
73 | error(context, methodInfo, error) {
74 | let logFields = { stack: error.stack };
75 |
76 | if (error instanceof ServiceError) {
77 | logFields = error.logFields();
78 | }
79 | if (methodInfo) {
80 | logFields.method = methodInfo.name;
81 | }
82 |
83 | this._log(context, error.message, logFields, 'error');
84 | }
85 |
86 | event(context, eventInfo, args) {
87 | this._log(context, `event: "${eventInfo.name}"`, {
88 | event: eventInfo.name,
89 | args: this._stringify(args, null, 2),
90 | });
91 | }
92 |
93 | subscribe(context, eventInfo) {
94 | this._log(context, `subscribed to event "${eventInfo.name}"`, { event: eventInfo.name });
95 | }
96 |
97 | unsubscribe(context, eventInfo) {
98 | this._log(context, `unsubscribed from event "${eventInfo.name}"`, {
99 | event: eventInfo.name,
100 | });
101 | }
102 | }
103 |
104 | module.exports = Trace;
105 |
--------------------------------------------------------------------------------
/lib/error.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const uuid = require('node-uuid');
4 |
5 | /**
6 | * Structured error containing context.
7 | * @extends Error
8 | */
9 | class ServiceError {
10 | /**
11 | * Create a structured error. Required properties are id, reporter, code and timestamp.
12 | *
13 | * @param {string} reporter The name of the entity which reports the error.
14 | * @param {number} code System-wide unique integer that identifies a specific type of error.
15 | * @param {object} details Information about the context of the error.
16 | * @param {string} details.message Human-readable short error message.
17 | * @param {ServiceError} details.cause The cause of the error.
18 | * @param {object} details.metadata Error payload which provides additional context.
19 | */
20 | constructor(reporter, code, { message, cause, metadata }) {
21 | Error.captureStackTrace(this, this.constructor);
22 |
23 | this.id = uuid.v4();
24 | this.reporter = reporter;
25 | this.code = code;
26 | this.message = message;
27 | this.cause = cause;
28 | this.metadata = metadata;
29 | this.timestamp = new Date();
30 | }
31 |
32 | /**
33 | * Presents the error in an appropriate format.
34 | * @returns {string}
35 | */
36 | toString() {
37 | let output =
38 | `reporter: ${this.reporter}\n` + `code: ${this.code}\n` + `message: ${this.message}\n`;
39 | if (this.cause) {
40 | output += `cause: ${this.cause.code} ${this.cause.message}\n`;
41 | }
42 | return output + `metadata: ${JSON.stringify(this.metadata)}`;
43 | }
44 |
45 | logFields() {
46 | return {
47 | id: this.id,
48 | reporter: this.reporter,
49 | code: this.code,
50 | message: this.message,
51 | cause: this.cause,
52 | metadata: this.metadata,
53 | stack: this.stack,
54 | errorTimestamp: this.timestamp,
55 | };
56 | }
57 | }
58 |
59 | const codes = {
60 | InternalServerError: 100,
61 | };
62 |
63 | module.exports = ServiceError;
64 |
65 | module.exports.AsServiceError = (err, reporter, code, metadata) => {
66 | code = code || code === 0 ? code : codes.InternalServerError;
67 |
68 | if (err instanceof ServiceError) {
69 | err.code = err.code || err.code === 0 ? err.code : codes.InternalServerError;
70 | if (reporter && err.reporter !== reporter) {
71 | return new ServiceError(reporter, err.code, {
72 | message: err.message,
73 | cause: err,
74 | metadata,
75 | });
76 | }
77 | return err;
78 | }
79 |
80 | // Check for a JSON-RPC error.
81 | if (err.hasOwnProperty('data')) {
82 | code = err.data.code || err.data.code === 0 ? err.data.code : code;
83 | return new ServiceError(reporter, code, {
84 | message: err.data.message,
85 | cause: err.data,
86 | metadata,
87 | });
88 | }
89 |
90 | if (err instanceof Error) {
91 | return new ServiceError(reporter, code, {
92 | message: err.message,
93 | metadata,
94 | });
95 | }
96 |
97 | return new ServiceError(reporter, code, {
98 | message: err,
99 | metadata,
100 | });
101 | };
102 |
--------------------------------------------------------------------------------
/proxies/stubs/csharp/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using ChaosGroup.JsonWS.Proxies;
4 | using Newtonsoft.Json.Linq;
5 |
6 | namespace csharp
7 | {
8 | internal class Program
9 | {
10 | private static void TestMethods()
11 | {
12 | using (var proxy = new GeneratedTest("http://localhost:3000/endpoint/1.0"))
13 | {
14 | try
15 | {
16 | Console.WriteLine(proxy/*.UseWS()*/.ThrowError().Result);
17 | }
18 | catch (Exception e)
19 | {
20 | Console.WriteLine(e.ToString());
21 | }
22 |
23 | var task = proxy.Sum(1, 2);
24 | Console.WriteLine(task.Result);
25 |
26 | var r = new GeneratedTest.RenderOptions {width = 1, height = 2, renderMode = GeneratedTest.RenderMode.Production};
27 | var taskEcho = proxy.Echo(r);
28 | Console.WriteLine(taskEcho.Result.ToString());
29 |
30 | var o = new JObject();
31 | o["a"] = JToken.FromObject(new[] { 1, 2 });
32 | var taskEcho2 = proxy.EchoObject(o);
33 | Console.WriteLine(taskEcho2.Result.ToString());
34 |
35 | // binary message
36 | var bytes = proxy.EchoStringAsBuffer("binary").Result;
37 | Console.WriteLine("bytes: {0}, message: {1}", bytes.Length,
38 | System.Text.Encoding.Default.GetString(bytes));
39 |
40 | var bytesLength = proxy.GetBufferSize(bytes).Result;
41 | Console.WriteLine("bytes buffer size: {0}", bytesLength);
42 | }
43 | }
44 |
45 | private static void TestEvents()
46 | {
47 | using (var proxy = new GeneratedTest("http://localhost:3000/endpoint/1.0"))
48 | {
49 | int n1 = 0;
50 | int n2 = 0;
51 | int n3 = 0;
52 |
53 | proxy.TestEvent2 += (sender, data) =>
54 | {
55 | Console.WriteLine("event2:{0}", data.Data[0].width);
56 | n2++;
57 | };
58 |
59 | proxy.TestEvent += (sender, data) =>
60 | {
61 | Console.WriteLine("event1:{0}", data.Data);
62 | n1++;
63 | };
64 |
65 | proxy.TestEvent3 += (sender, data) =>
66 | {
67 | Console.WriteLine("event3:{0}", data.Data);
68 | n3++;
69 | };
70 |
71 | for (long i = 0, prev = i; i < 20; i++)
72 | {
73 | Console.WriteLine(prev = proxy.UseWS().Sum(i, prev).Result);
74 | }
75 |
76 | Thread.Sleep(10000);
77 | Console.WriteLine("{0}, {1}, {2}", n1, n2, n3);
78 | }
79 | }
80 |
81 | private static void TestUnsubscribe()
82 | {
83 | var proxy = new GeneratedTest("http://localhost:3000/endpoint/1.0");
84 | int n1 = 0;
85 | EventHandler