Remove universal decoder (#2068)
This commit is contained in:
Родитель
1d0df74355
Коммит
da7d8a0d1d
|
@ -1,103 +0,0 @@
|
|||
name: Universal Decoder CI
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- dev
|
||||
paths:
|
||||
- 'Samples/UniversalDecoder/**'
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- dev
|
||||
paths:
|
||||
- 'Samples/UniversalDecoder/**'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
pushDockerImage:
|
||||
description: 'Push docker image to the repository'
|
||||
type: boolean
|
||||
required: false
|
||||
default: 'false'
|
||||
|
||||
jobs:
|
||||
Build_And_Test:
|
||||
name: Build and Test Solution
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./Samples/UniversalDecoder
|
||||
env:
|
||||
DOCKER_REPOSITORY: ${{ secrets.DOCKER_REPOSITORY }}
|
||||
DOCKER_LOGIN: ${{ secrets.DOCKER_LOGIN }}
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
steps:
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v3
|
||||
- name: Use node JS
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '14'
|
||||
- run: npm install
|
||||
- name: Get vendor file
|
||||
run: npm run codecs
|
||||
- name: Run Tests
|
||||
run: npm test
|
||||
|
||||
Build_And_Push:
|
||||
name: Build and Push Solution
|
||||
needs: Build_And_Test
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
image:
|
||||
- arm32v7
|
||||
- arm64v8
|
||||
- amd64
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./Samples/UniversalDecoder
|
||||
outputs:
|
||||
tag: ${{ steps.vars.outputs.tag }}
|
||||
steps:
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v3
|
||||
- uses: docker/setup-buildx-action@v2
|
||||
id: buildx
|
||||
with:
|
||||
install: true
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Use node JS
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '14'
|
||||
- run: npm install
|
||||
- name: Get vendor file
|
||||
run: npm run codecs
|
||||
- name: Get the image version
|
||||
id: vars
|
||||
run: echo ::set-output name=tag::0.0.$(echo ${GITHUB_SHA})
|
||||
- name: Login to Docker, and build and push the tagged Docker image
|
||||
if: ${{ github.event.inputs.pushDockerImage == 'true' }}
|
||||
run: |
|
||||
docker login -u ${{ secrets.DOCKER_LOGIN }} -p ${{ secrets.DOCKER_PASSWORD }}
|
||||
docker buildx build -f "Dockerfile.${{ matrix.image }}" -t ${{ secrets.DOCKER_REPOSITORY }}/universaldecoder:${{steps.vars.outputs.tag}}-${{ matrix.image }} --output type=image,push=true "."
|
||||
- name: Build the tagged Docker image without push
|
||||
if: ${{ github.event.inputs.pushDockerImage == 'false' }}
|
||||
run: docker buildx build -f "Dockerfile.${{ matrix.image }}" -t ${{ secrets.DOCKER_REPOSITORY }}/universaldecoder:${{steps.vars.outputs.tag}}-${{ matrix.image }} "."
|
||||
|
||||
Docker_Manifests:
|
||||
if: ${{ github.event.inputs.pushDockerImage == 'true' }}
|
||||
name: Create manifests
|
||||
runs-on: ubuntu-latest
|
||||
needs: Build_And_Push
|
||||
steps:
|
||||
- run: echo "output ${{needs.Test_And_Push.outputs.tag}}"
|
||||
- name: Login to docker registry
|
||||
run: docker login -u ${{ secrets.DOCKER_LOGIN }} -p ${{ secrets.DOCKER_PASSWORD }}
|
||||
- name: Create manifest list
|
||||
run: docker manifest create ${{ secrets.DOCKER_REPOSITORY }}/universaldecoder:${{needs.Build_And_Push.outputs.tag}} ${{ secrets.DOCKER_REPOSITORY }}/universaldecoder:${{needs.Build_And_Push.outputs.tag}}-arm32v7 ${{ secrets.DOCKER_REPOSITORY }}/universaldecoder:${{needs.Build_And_Push.outputs.tag}}-amd64 ${{ secrets.DOCKER_REPOSITORY }}/universaldecoder:${{needs.Build_And_Push.outputs.tag}}-arm64v8 --amend
|
||||
- name: Push manifest
|
||||
run: docker manifest push ${{ secrets.DOCKER_REPOSITORY }}/universaldecoder:${{needs.Build_And_Push.outputs.tag}}
|
||||
|
|
@ -3,5 +3,3 @@
|
|||
The following samples are available:
|
||||
|
||||
- [Decoder](https://azure.github.io/iotedge-lorawan-starterkit/samples/decoders/decoder/)
|
||||
- [UniversalDecoder](https://azure.github.io/iotedge-lorawan-starterkit/samples/decoders/universal/)
|
||||
- [CayenneDecoder](https://azure.github.io/iotedge-lorawan-starterkit/samples/decoders/cayenne/)
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
# NOTE: Use either docker.io or your own registry address to build the image
|
||||
ARG SOURCE_CONTAINER_REGISTRY_ADDRESS=your-registry-address.azurecr.io
|
||||
FROM $SOURCE_CONTAINER_REGISTRY_ADDRESS/amd64/node:14-alpine
|
||||
|
||||
WORKDIR /app/
|
||||
|
||||
COPY package*.json ./
|
||||
COPY NOTICE.txt ./
|
||||
|
||||
RUN npm install --production
|
||||
|
||||
COPY *.js ./
|
||||
COPY codecs ./codecs
|
||||
|
||||
USER node
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
CMD ["node", "app.js"]
|
|
@ -1,19 +0,0 @@
|
|||
# NOTE: Use either docker.io or your own registry address to build the image
|
||||
ARG SOURCE_CONTAINER_REGISTRY_ADDRESS=your-registry-address.azurecr.io
|
||||
FROM $SOURCE_CONTAINER_REGISTRY_ADDRESS/arm32v7/node:14-slim
|
||||
|
||||
WORKDIR /app/
|
||||
|
||||
COPY package*.json ./
|
||||
COPY NOTICE.txt ./
|
||||
|
||||
RUN npm install --production
|
||||
|
||||
COPY *.js ./
|
||||
COPY codecs ./codecs
|
||||
|
||||
USER node
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
CMD ["node", "app.js"]
|
|
@ -1,19 +0,0 @@
|
|||
# NOTE: Use either docker.io or your own registry address to build the image
|
||||
ARG SOURCE_CONTAINER_REGISTRY_ADDRESS=your-registry-address.azurecr.io
|
||||
FROM $SOURCE_CONTAINER_REGISTRY_ADDRESS/arm64v8/node:14-slim
|
||||
|
||||
WORKDIR /app/
|
||||
|
||||
COPY package*.json ./
|
||||
COPY NOTICE.txt ./
|
||||
|
||||
RUN npm install --production
|
||||
|
||||
COPY *.js ./
|
||||
COPY codecs ./codecs
|
||||
|
||||
USER node
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
CMD ["node", "app.js"]
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,51 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
const {logger} = require('./app.logging');
|
||||
|
||||
const decoders = (() => {
|
||||
try {
|
||||
return require('./codecs');
|
||||
} catch (e) {
|
||||
if (e instanceof Error && e.code === 'MODULE_NOT_FOUND') {
|
||||
return {};
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
function getAllDecoders() {
|
||||
return Object.keys(decoders);
|
||||
}
|
||||
|
||||
// gets decoder by name
|
||||
function getDecoder(decoderName) {
|
||||
if (decoderName === 'DecoderValueSensor') {
|
||||
// return inline decoder implementation
|
||||
return {
|
||||
decodeUplink: (input) => { return { data: input.bytes.join('') } }
|
||||
}
|
||||
}
|
||||
const decoder = decoders[decoderName];
|
||||
if (!decoder) {
|
||||
throw new Error(`No codec found: ${decoderName}`);
|
||||
}
|
||||
return decoder;
|
||||
}
|
||||
|
||||
function decode(decoderName, payload, fPort) {
|
||||
const decoder = getDecoder(decoderName);
|
||||
|
||||
const input = {
|
||||
bytes: Buffer.from(payload, 'base64').toString('utf8').split(''),
|
||||
fPort: parseInt(fPort)
|
||||
};
|
||||
|
||||
logger.debug(`Decoder ${decoderName} input: ${JSON.stringify(input)}`);
|
||||
const output = decoder.decodeUplink(input);
|
||||
logger.debug(`Decoder ${decoderName} output: ${JSON.stringify(output)}`);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
module.exports = { getAllDecoders, decode };
|
|
@ -1,8 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
const port = 8080;
|
||||
|
||||
const app = require('./app.routes');
|
||||
app.listen(port, () => {
|
||||
console.log(`Server started at http://localhost:${port}`)
|
||||
})
|
|
@ -1,24 +0,0 @@
|
|||
'use strict'
|
||||
|
||||
const pino = require('pino');
|
||||
const expressPino = require('express-pino-logger');
|
||||
|
||||
const logger = pino({ level: process.env.LOG_LEVEL || 'info' });
|
||||
const expressLogger = expressPino({
|
||||
logger,
|
||||
serializers: {
|
||||
req: (req) => ({
|
||||
method: req.method,
|
||||
url: req.url,
|
||||
}),
|
||||
res: (res) => ({
|
||||
statusCode: res.statusCode,
|
||||
}),
|
||||
err: (err) => ({
|
||||
type: err.type,
|
||||
message: err.message
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = {logger, expressLogger};
|
|
@ -1,44 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
const express = require('express');
|
||||
const {param, query, validationResult} = require('express-validator');
|
||||
const {expressLogger, logger} = require('./app.logging');
|
||||
const decoder = require('./app.decoder');
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(expressLogger);
|
||||
|
||||
app.get('/decoders', (req, res, next) => {
|
||||
res.send(decoder.getAllDecoders());
|
||||
});
|
||||
|
||||
app.get('/api/:decodername',
|
||||
param('decodername').notEmpty().withMessage("is missing"),
|
||||
query('payload').notEmpty().withMessage("is missing").isBase64().withMessage("must be a base64 encoded string"),
|
||||
query('fport').isInt(),
|
||||
(req, res, next) => {
|
||||
// Input validation
|
||||
if (!validationResult(req).isEmpty()) {
|
||||
const error = `Invalid inputs: ${(validationResult(req).formatWith(e => `'${e.param}' ${e.msg}`).array().join(", "))}`;
|
||||
logger.warn(error);
|
||||
return res.status(400).send({error});
|
||||
}
|
||||
|
||||
const output = decoder.decode(req.params.decodername, req.query.payload, req.query.fport);
|
||||
|
||||
res.send({
|
||||
value: output.data,
|
||||
});
|
||||
});
|
||||
|
||||
// Error handling
|
||||
app.use(function (err, req, res, next) {
|
||||
logger.error(err);
|
||||
res.status(500).send({
|
||||
error: err.message,
|
||||
rawPayload: req.query.payload
|
||||
});
|
||||
})
|
||||
|
||||
module.exports = app;
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"Registrations": [
|
||||
{
|
||||
"Component": {
|
||||
"Type": "git",
|
||||
"git": {
|
||||
"RepositoryUrl": "https://github.com/TheThingsNetwork/lorawan-devices",
|
||||
"CommitHash": "de9ebd35677bdd36887019e6c3d319bc4b35615e"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
{
|
||||
"$schema-version": "0.0.1",
|
||||
"description": "Universal decoder",
|
||||
"image": {
|
||||
"repository": "oneweek202105.azurecr.io/universaldecoder",
|
||||
"tag": {
|
||||
"version": "0.0.7",
|
||||
"platforms": {
|
||||
"amd64": "./Dockerfile.amd64",
|
||||
"arm32v7": "./Dockerfile.arm32v7",
|
||||
"arm64v8": "./Dockerfile.arm64v8"
|
||||
}
|
||||
},
|
||||
"buildOptions": []
|
||||
},
|
||||
"language": "javascript"
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"name": "universaldecoder",
|
||||
"version": "0.0.1",
|
||||
"description": "Universal decoder module for LoraWan",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Azure/generator-azure-iot-edge-module"
|
||||
},
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"start": "LOG_LEVEL=debug node app.js | ./node_modules/.bin/pino-pretty",
|
||||
"test": "jest",
|
||||
"codecs": "rm -fR node_modules/lorawan-devices codecs/* && git clone --depth 1 https://github.com/TheThingsNetwork/lorawan-devices.git node_modules/lorawan-devices && node tools/copy-codecs.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"esprima-next": "^5.8.4",
|
||||
"express": "^4.18.2",
|
||||
"express-pino-logger": "^7.0.0",
|
||||
"express-validator": "^6.14.1",
|
||||
"fs-extra": "^11.1.0",
|
||||
"glob": "^8.0.3",
|
||||
"pino": "^8.8.0",
|
||||
"pino-pretty": "^9.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jest": "^29.3.1",
|
||||
"supertest": "^6.3.3"
|
||||
},
|
||||
"jest": {
|
||||
"testEnvironment": "node",
|
||||
"transformIgnorePatterns": [
|
||||
"/codecs/"
|
||||
],
|
||||
"coveragePathIgnorePatterns": [
|
||||
"/node_modules/"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,145 +0,0 @@
|
|||
const request = require('supertest')
|
||||
const app = require('../app.routes')
|
||||
|
||||
describe('DecoderValueSensor', () => {
|
||||
it('should decode basic data', async () => {
|
||||
const res = await sendRequest('DecoderValueSensor', 'ABCDE12345', 1);
|
||||
expect(res.statusCode).toEqual(200);
|
||||
expect(res.body).toEqual({
|
||||
value: 'ABCDE12345',
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle missing parameters', async () => {
|
||||
const res = await request(app)
|
||||
.get(`/api/DecoderValueSensor`)
|
||||
.send();
|
||||
expect(res.statusCode).toEqual(400);
|
||||
expect(res.body).toEqual({
|
||||
error: 'Invalid inputs: \'payload\' is missing, \'fport\' Invalid value',
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle wrong payload', async () => {
|
||||
const res = await request(app)
|
||||
.get(`/api/DecoderValueSensor`)
|
||||
.query({
|
||||
payload: "not-base64",
|
||||
fport: 1,
|
||||
})
|
||||
.send();
|
||||
expect(res.statusCode).toEqual(400);
|
||||
expect(res.body).toEqual({
|
||||
error: 'Invalid inputs: \'payload\' must be a base64 encoded string',
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle wrong fPort', async () => {
|
||||
const res = await sendRequest('DecoderValueSensor', 'ABCDE12345', "not-int");
|
||||
expect(res.statusCode).toEqual(400);
|
||||
expect(res.body).toEqual({
|
||||
error: 'Invalid inputs: \'fport\' Invalid value',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('invalid-decoder', () => {
|
||||
it('should return error', async () => {
|
||||
const res = await sendRequest('invalid-decoder', 'ABCDE12345', 1);
|
||||
expect(res.statusCode).toEqual(500);
|
||||
expect(res.body).toEqual({
|
||||
error: "No codec found: invalid-decoder",
|
||||
rawPayload: "QUJDREUxMjM0NQ=="
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('loravisionshield', () => {
|
||||
it('should decode led state on', async () => {
|
||||
const res = await sendRequest('loravisionshield', '1', 1);
|
||||
expect(res.statusCode).toEqual(200);
|
||||
expect(res.body).toEqual({
|
||||
value: {
|
||||
ledState: "on"
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should decode led state off', async () => {
|
||||
const res = await sendRequest('loravisionshield', '0', 1);
|
||||
expect(res.statusCode).toEqual(200);
|
||||
expect(res.body).toEqual({
|
||||
value: {
|
||||
ledState: "off"
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('tpl110-0292', () => {
|
||||
it('should decode parking status occupied', async () => {
|
||||
const res = await sendRequest('tpl110-0292', '1', 1);
|
||||
expect(res.statusCode).toEqual(200);
|
||||
expect(res.body).toEqual({
|
||||
value: {
|
||||
type: "parking status",
|
||||
occupied: true
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should decode parking status not occupied', async () => {
|
||||
const res = await sendRequest('tpl110-0292', '0', 1);
|
||||
expect(res.statusCode).toEqual(200);
|
||||
expect(res.body).toEqual({
|
||||
value: {
|
||||
type: "parking status",
|
||||
occupied: false
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should decode device heartbeat', async () => {
|
||||
const res = await sendRequest('tpl110-0292', '1111', 2);
|
||||
expect(res.statusCode).toEqual(200);
|
||||
expect(res.body).toEqual({
|
||||
value: {
|
||||
occupied: true,
|
||||
temperature: "1",
|
||||
type: "heartbeat"
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// The following test has been disabled because decoder script was changed
|
||||
// A fix in copy-codecs.js is required to re-enable the import of this decoder #1833
|
||||
// describe('lw001-bg', () => {
|
||||
// it('should decode all 1s', async () => {
|
||||
// const res = await sendRequest('lw001-bg', '1111111111111111', 1);
|
||||
// expect(res.statusCode).toEqual(200);
|
||||
// expect(res.body).toEqual({
|
||||
// value: {
|
||||
// barometer: 65792.1,
|
||||
// batterylevel: 0.01,
|
||||
// devicestatus: "1",
|
||||
// firmwareversion: 101,
|
||||
// humidity: 25.61,
|
||||
// macversion: 0,
|
||||
// temperature: -19.39,
|
||||
// type: "Device Information Packet"
|
||||
// },
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
|
||||
function sendRequest(decoderName, payload, fPort) {
|
||||
return request(app)
|
||||
.get(`/api/${decoderName}`)
|
||||
.query({
|
||||
payload: Buffer.from(payload).toString('base64'),
|
||||
fport: fPort,
|
||||
devEui: "0000000000000000",
|
||||
})
|
||||
.send();
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
const glob = require('glob');
|
||||
const fs = require('fs');
|
||||
const fse = require('fs-extra');
|
||||
const path = require('path');
|
||||
const esprima = require('esprima-next');
|
||||
|
||||
var args = process.argv.slice(2);
|
||||
const srcDir = args[0] || './node_modules/lorawan-devices/vendor';
|
||||
const dstDir = args[1] || './codecs';
|
||||
const indexFilePath = path.join(dstDir, 'index.js');
|
||||
const index = glob.sync(`**/*`,
|
||||
{
|
||||
cwd: srcDir,
|
||||
nodir: true,
|
||||
ignore: [
|
||||
'**/*.jpg',
|
||||
'**/*.png',
|
||||
'**/*.svg',
|
||||
]
|
||||
}).map(f => {
|
||||
const srcPath = `${srcDir}/${f}`;
|
||||
const dstPath = `${dstDir}/${f}`;
|
||||
|
||||
console.log(`Copying ${srcPath} to ${dstPath}`);
|
||||
fse.copySync(srcPath, dstPath);
|
||||
|
||||
if (f.endsWith(".js")) {
|
||||
// Sniff a top-level declaration for a function named "decodeUplink"
|
||||
// and include the decoder if only one is found.
|
||||
const tree = esprima.parseScript(fs.readFileSync(srcPath).toString());
|
||||
if (tree.body.find(n => n.type === 'FunctionDeclaration' && n.id.name === 'decodeUplink')) {
|
||||
fs.appendFile(dstPath, '\nmodule.exports={decodeUplink};', function (err) {
|
||||
if (err) throw err;
|
||||
console.log(`Patching ${dstPath}`);
|
||||
});
|
||||
return dstPath;
|
||||
}
|
||||
}
|
||||
})
|
||||
.filter(f => f)
|
||||
.map(f => [path.basename(f).split('.')[0], path.relative(dstDir, f).replace(/\\/g, '/')]);
|
||||
|
||||
fs.writeFileSync(indexFilePath,
|
||||
`module.exports = {\n${index.map(([k, v]) => `${JSON.stringify(k)}: require(${JSON.stringify('./' + v)})`).join(',\n ')}\n};\n`);
|
Загрузка…
Ссылка в новой задаче