diff --git a/swagger/sdrangel/.gitignore b/swagger/sdrangel/.gitignore new file mode 100644 index 000000000..65f91cd1a --- /dev/null +++ b/swagger/sdrangel/.gitignore @@ -0,0 +1,34 @@ +# IDE files +.idea + +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +# Commenting this out is preferred by some people, see +# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git +node_modules + +# Users Environment Variables +.lock-wscript + +# Runtime configuration for swagger app +config/runtime.yaml diff --git a/swagger/sdrangel/README.md b/swagger/sdrangel/README.md new file mode 100644 index 000000000..2249faca3 --- /dev/null +++ b/swagger/sdrangel/README.md @@ -0,0 +1,59 @@ +# Swagger project for SDRangel + +

What is Swagger?

+ +Swagger is an open source software framework backed by a large ecosystem of tools that helps developers design, build, document, and consume RESTful Web services. [Link to Swagger website](https://swagger.io/) + +Swagger is used to design the SDRangel web API. You will find the Swagger framework for SDRangel here. + +

Install Swagger

+ +Uses `apt-get` package manager (Ubuntu, Debian). Use your distribution package manager for other distributions + +```shell +sudo apt-get install npm +sudo npm install -g swagger +``` + +install Node.js 6.x on Ubuntu 16.04 : + +```shell +curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash - +sudo apt-get install -y nodejs +``` +Install http-server a lightweight web server to serve included files + +```shell +sudo npm install -g http-server +``` + +

Work with Swagger

+ +

Edit files with Swagger

+ +All commands are relative to this directory (where the README.md is) + +Firstly start a node server to serve files in `api/swagger/include` + +```shell +cd api/swagger/include +http-server --cors . +``` + +Then in start the swagger editor + +```shell +swagger project edit +``` + +

Mocking

+ +Write controllers for mocking in `api/mocks/` + +Run the server in mock mode: + +```shell +swagger project start -m +``` + + diff --git a/swagger/sdrangel/api/controllers/README.md b/swagger/sdrangel/api/controllers/README.md new file mode 100644 index 000000000..ddb3f6488 --- /dev/null +++ b/swagger/sdrangel/api/controllers/README.md @@ -0,0 +1 @@ +Place your controllers in this directory. diff --git a/swagger/sdrangel/api/controllers/hello_world.js b/swagger/sdrangel/api/controllers/hello_world.js new file mode 100644 index 000000000..2e17de72b --- /dev/null +++ b/swagger/sdrangel/api/controllers/hello_world.js @@ -0,0 +1,44 @@ +'use strict'; +/* + 'use strict' is not required but helpful for turning syntactical errors into true errors in the program flow + https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode +*/ + +/* + Modules make it possible to import JavaScript files into your application. Modules are imported + using 'require' statements that give you a reference to the module. + + It is a good idea to list the modules that your application depends on in the package.json in the project root + */ +var util = require('util'); + +/* + Once you 'require' a module you can reference the things that it exports. These are defined in module.exports. + + For a controller in a127 (which this is) you should export the functions referenced in your Swagger document by name. + + Either: + - The HTTP Verb of the corresponding operation (get, put, post, delete, etc) + - Or the operationId associated with the operation in your Swagger document + + In the starter/skeleton project the 'get' operation on the '/hello' path has an operationId named 'hello'. Here, + we specify that in the exports of this module that 'hello' maps to the function named 'hello' + */ +module.exports = { + hello: hello +}; + +/* + Functions in a127 controllers used for operations should take two parameters: + + Param 1: a handle to the request object + Param 2: a handle to the response object + */ +function hello(req, res) { + // variables defined in the Swagger document can be referenced using req.swagger.params.{parameter_name} + var name = req.swagger.params.name.value || 'stranger'; + var hello = util.format('Hello, %s!', name); + + // this sends back a JSON response which is a single string + res.json(hello); +} diff --git a/swagger/sdrangel/api/helpers/README.md b/swagger/sdrangel/api/helpers/README.md new file mode 100644 index 000000000..36a598fd0 --- /dev/null +++ b/swagger/sdrangel/api/helpers/README.md @@ -0,0 +1 @@ +Place helper files in this directory. diff --git a/swagger/sdrangel/api/mocks/README.md b/swagger/sdrangel/api/mocks/README.md new file mode 100644 index 000000000..8069e63b0 --- /dev/null +++ b/swagger/sdrangel/api/mocks/README.md @@ -0,0 +1,5 @@ +

This directory contains the controller files to support the mock server

+ +

Controllers

+ + - `instance.js`: methods found in the `/sdrangel` route diff --git a/swagger/sdrangel/api/mocks/instance.js b/swagger/sdrangel/api/mocks/instance.js new file mode 100644 index 000000000..b71788672 --- /dev/null +++ b/swagger/sdrangel/api/mocks/instance.js @@ -0,0 +1,211 @@ +'use strict'; + +module.exports = { + instanceSummary: instanceSummary, + instanceDevices: instanceDevices, + instanceChannels: instanceChannels +}; + +function instanceSummary(req, res, next) { + + res.json([ + { + "version":"4.0.0", + "logging": { + "consoleLevel": "info", + "fileLevel": "debug", + "dumpToFile": false + }, + "devicesetcount":2, + "devicesets":[ + { + "samplingDevice": { + "index":0, + "hwType":"RTLSDR", + "rx":true, + "streamIndex":0, + "sequence":0, + "serial":"R820T2005", + "centerFrequency": 435000000, + "bandwidth": 64000 + }, + "channelcount":2, + "channels":[ + {"index":0,"id":"AMDemod","deltaFrequency":-12500}, + {"index":1,"id":"AMDemod","deltaFrequency":12500} + ] + }, + { + "samplingDevice": { + "index":1, + "hwType":"HackRF", + "rx":false, + "streamIndex":0, + "sequence":0, + "serial":"453c64c8257a608f", + "centerFrequency": 435000000, + "bandwidth": 128000 + }, + "channelcount":1, + "channels":[ + {"index":0,"id":"AMMod","deltaFrequency":12500} + ] + } + + ], + "user":{"index":1,"name":"Sample text"}} + ]); +} + +function instanceDevices(req, res, next) { + var direction = req.swagger.params.direction.value || "rx"; + //console.log(direction.value) + + if (direction === "tx") { + res.json([ + { + "devicecount": 1, + "devices": [ + { + "hwType":"HackRF", + "rx":false, + "streamIndex":0, + "sequence":0, + "serial":"453c64c8257a608f" + } + ] + }]); + } else { + res.json([ + { + "devicecount": 2, + "devices": [ + { + "hwType":"RTLSDR", + "rx":true, + "streamIndex":0, + "sequence":0, + "serial":"R820T2005" + }, + { + "hwType":"HackRF", + "rx":true, + "streamIndex":0, + "sequence":0, + "serial":"453c64c8257a608f" + } + ] + }]); + } +} + +function instanceChannels(req, res, next) { + var direction = req.swagger.params.direction.value || "rx"; + + if (direction === "tx") { + res.json([ + { + "channelcount": 6, + "channels": [ + { + "name":"AM Modulator", + "id": "AMMod", + "rx":false, + "version": "3.9.0" + }, + { + "name":"ATV Modulator", + "id": "ATVMod", + "rx":false, + "version": "3.9.0" + }, + { + "name":"NFM Modulator", + "id": "NFMMod", + "rx":false, + "version": "3.9.0" + }, + { + "name":"SSB Modulator", + "id": "SSBMod", + "rx":false, + "version": "3.9.0" + }, + { + "name":"UDP Channel Sink", + "id": "UDPSink", + "rx":false, + "version": "4.0.0" + }, + { + "name":"WFM Modulator", + "id": "WFMMod", + "rx":false, + "version": "3.9.0" + } + ] + }]); + } else { + res.json([ + { + "channelcount": 9, + "channels": [ + { + "name":"AM Demodulator", + "id": "AMemod", + "rx":true, + "version": "4.0.0" + }, + { + "name":"Broadcast FM Demodulator", + "id": "BFMDemod", + "rx":true, + "version": "4.0.0" + }, + { + "name":"ATV Demodulator", + "id": "ATVDemod", + "rx":true, + "version": "4.0.0" + }, + { + "name":"DSD Demodulator", + "id": "DSDDemod", + "rx":true, + "version": "4.0.0" + }, + { + "name":"NFM Demodulator", + "id": "NFDemod", + "rx":true, + "version": "4.0.0" + }, + { + "name":"SSB Demodulator", + "id": "SSBDemod", + "rx":true, + "version": "4.0.0" + }, + { + "name":"TCP Channel Source", + "id": "TCPSource", + "rx":true, + "version": "4.0.0" + }, + { + "name":"UDP Channel Source", + "id": "UDPSource", + "rx":true, + "version": "4.0.0" + }, + { + "name":"WFM Demodulator", + "id": "WFMDemod", + "rx":true, + "version": "4.0.0" + } + ] + }]); + } + +} diff --git a/swagger/sdrangel/api/swagger/include/User.yaml b/swagger/sdrangel/api/swagger/include/User.yaml new file mode 100644 index 000000000..e4c4ca4c8 --- /dev/null +++ b/swagger/sdrangel/api/swagger/include/User.yaml @@ -0,0 +1,9 @@ +User: + required: + - index + - name + properties: + index: + type: integer + name: + type: string diff --git a/swagger/sdrangel/api/swagger/swagger.yaml b/swagger/sdrangel/api/swagger/swagger.yaml new file mode 100644 index 000000000..9451edf37 --- /dev/null +++ b/swagger/sdrangel/api/swagger/swagger.yaml @@ -0,0 +1,229 @@ +swagger: "2.0" +info: + version: "4.0.0" + title: SDRangel +# during dev, should point to your local machine +host: localhost:10010 +# basePath prefixes all resource paths +basePath: / +# +schemes: + # tip: remove http to make production-grade + - http + - https +# format of bodies a client can send (Content-Type) +consumes: + - application/json +# format of the responses to the client (Accepts) +produces: + - application/json +paths: + /sdrangel: + # binds a127 app logic to a route + x-swagger-router-controller: instance + get: + description: SDRangel instance summary + # used as the method name of the controller + operationId: instanceSummary + # parameters: + # - name: name + # in: query + # description: The name of the person to whom to say hello + # required: false + # type: string + responses: + "200": + description: Success + schema: + # a pointer to a definition + $ref: "#/definitions/InstanceSummaryResponse" + # responses may fall through to errors + default: + description: Error + schema: + $ref: "#/definitions/ErrorResponse" + /sdrangel/devices: + x-swagger-router-controller: instance + get: + description: Get a list of sampling devices + operationId: instanceDevices + parameters: + - name: direction + in: query + description: gives Rx or Tx direction + required: false + type: string + responses: + "200": + description: Success + schema: + $ref: "#/definitions/InstanceDevicesResponse" + default: + description: Error + schema: + $ref: "#/definitions/ErrorResponse" + /sdrangel/channels: + x-swagger-router-controller: instance + get: + description: Get a list of channel plugins + operationId: instanceChannels + parameters: + - name: direction + in: query + description: gives Rx or Tx direction + required: false + type: string + responses: + "200": + description: Success + schema: + $ref: "#/definitions/InstanceChannelsResponse" + default: + description: Error + schema: + $ref: "#/definitions/ErrorResponse" + /swagger: + x-swagger-pipe: swagger_raw +# complex objects have schema definitions +definitions: + InstanceSummaryResponse: + required: + - version + - devicesetcount + properties: + version: + type: string + logging: + $ref: "#/definitions/LoggingInfo" + devicesetcount: + type: integer + devicesets: + type: array + items: + $ref: "#/definitions/DeviceSet" + user: + $ref: "http://localhost:8080/User.yaml#/User" + InstanceDevicesResponse: + required: + - devicecount + properties: + devicecount: + type: integer + devices: + type: array + items: + $ref: "#/definitions/DeviceListItem" + InstanceChannelsResponse: + required: + - channelcount + properties: + channelcount: + type: integer + channels: + type: array + items: + $ref: "#/definitions/ChannelListItem" + ErrorResponse: + required: + - message + properties: + message: + type: string + LoggingInfo: + required: + - consoleLevel + - fileLevel + - dumpToFile + properties: + consoleLevel: + type: string + fileLevel: + type: string + dumpToFile: + type: boolean + fileName: + type: string + DeviceListItem: + required: + - hwType + - rx + - streamIndex + - sequence + - serial + properties: + hwType: + type: string + rx: + type: boolean + streamIndex: + type: integer + sequence: + type: integer + serial: + type: string + ChannelListItem: + required: + - name + - id + - rx + properties: + name: + type: string + id: + type: string + rx: + type: boolean + version: + type: string + DeviceSet: + required: + - samplingDevice + - channelcount + properties: + samplingDevice: + $ref: "#/definitions/SamplingDevice" + channelcount: + type: integer + channels: + type: array + items: + $ref: "#/definitions/Channel" + SamplingDevice: + required: + - index + - hwType + - rx + - streamIndex + - sequence + - serial + - centerFrequency + - bandwidth + properties: + index: + type: integer + hwType: + type: string + rx: + type: boolean + streamIndex: + type: integer + sequence: + type: integer + serial: + type: string + centerFrequency: + type: integer + bandwidth: + type: integer + Channel: + required: + - index + - id + - deltaFrequency + properties: + index: + type: integer + id: + type: string + deltaFrequency: + type: integer diff --git a/swagger/sdrangel/app.js b/swagger/sdrangel/app.js new file mode 100644 index 000000000..f4c29aba7 --- /dev/null +++ b/swagger/sdrangel/app.js @@ -0,0 +1,23 @@ +'use strict'; + +var SwaggerExpress = require('swagger-express-mw'); +var app = require('express')(); +module.exports = app; // for testing + +var config = { + appRoot: __dirname // required config +}; + +SwaggerExpress.create(config, function(err, swaggerExpress) { + if (err) { throw err; } + + // install middleware + swaggerExpress.register(app); + + var port = process.env.PORT || 10010; + app.listen(port); + + if (swaggerExpress.runner.swagger.paths['/hello']) { + console.log('try this:\ncurl http://127.0.0.1:' + port + '/hello?name=Scott'); + } +}); diff --git a/swagger/sdrangel/config/README.md b/swagger/sdrangel/config/README.md new file mode 100644 index 000000000..d0535bda1 --- /dev/null +++ b/swagger/sdrangel/config/README.md @@ -0,0 +1 @@ +Place configuration files in this directory. diff --git a/swagger/sdrangel/config/default.yaml b/swagger/sdrangel/config/default.yaml new file mode 100644 index 000000000..cbe55eba3 --- /dev/null +++ b/swagger/sdrangel/config/default.yaml @@ -0,0 +1,37 @@ +# swagger configuration file + +# values in the swagger hash are system configuration for swagger-node +swagger: + + fittingsDirs: [ api/fittings ] + defaultPipe: null + swaggerControllerPipe: swagger_controllers # defines the standard processing pipe for controllers + + # values defined in the bagpipes key are the bagpipes pipes and fittings definitions + # (see https://github.com/apigee-127/bagpipes) + bagpipes: + + _router: + name: swagger_router + mockMode: false + mockControllersDirs: [ api/mocks ] + controllersDirs: [ api/controllers ] + + _swagger_validate: + name: swagger_validator + validateResponse: true + + # pipe for all swagger-node controllers + swagger_controllers: + - onError: json_error_handler + - cors + - swagger_security + - _swagger_validate + - express_compatibility + - _router + + # pipe to serve swagger (endpoint is in swagger.yaml) + swagger_raw: + name: swagger_raw + +# any other values in this file are just loaded into the config for application access... diff --git a/swagger/sdrangel/package.json b/swagger/sdrangel/package.json new file mode 100644 index 000000000..e5a1a1aae --- /dev/null +++ b/swagger/sdrangel/package.json @@ -0,0 +1,22 @@ +{ + "name": "sdrangel", + "version": "4.0.0", + "private": true, + "description": "New Swagger API Project for SDRangel", + "keywords": [], + "author": "", + "license": "", + "main": "app.js", + "dependencies": { + "express": "^4.12.3", + "swagger-express-mw": "^0.1.0" + }, + "devDependencies": { + "should": "^7.1.0", + "supertest": "^1.0.0" + }, + "scripts": { + "start": "node app.js", + "test": "swagger project test" + } +} diff --git a/swagger/sdrangel/test/api/controllers/README.md b/swagger/sdrangel/test/api/controllers/README.md new file mode 100644 index 000000000..16437ee16 --- /dev/null +++ b/swagger/sdrangel/test/api/controllers/README.md @@ -0,0 +1 @@ +Place your controller tests in this directory. diff --git a/swagger/sdrangel/test/api/controllers/hello_world.js b/swagger/sdrangel/test/api/controllers/hello_world.js new file mode 100644 index 000000000..38f8093dc --- /dev/null +++ b/swagger/sdrangel/test/api/controllers/hello_world.js @@ -0,0 +1,48 @@ +var should = require('should'); +var request = require('supertest'); +var server = require('../../../app'); + +describe('controllers', function() { + + describe('hello_world', function() { + + describe('GET /hello', function() { + + it('should return a default string', function(done) { + + request(server) + .get('/hello') + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(200) + .end(function(err, res) { + should.not.exist(err); + + res.body.should.eql('Hello, stranger!'); + + done(); + }); + }); + + it('should accept a name parameter', function(done) { + + request(server) + .get('/hello') + .query({ name: 'Scott'}) + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(200) + .end(function(err, res) { + should.not.exist(err); + + res.body.should.eql('Hello, Scott!'); + + done(); + }); + }); + + }); + + }); + +}); diff --git a/swagger/sdrangel/test/api/helpers/README.md b/swagger/sdrangel/test/api/helpers/README.md new file mode 100644 index 000000000..8528f1b16 --- /dev/null +++ b/swagger/sdrangel/test/api/helpers/README.md @@ -0,0 +1 @@ +Place your helper tests in this directory.