mockサーバーを実装する
This commit is contained in:
parent
5e28005d75
commit
a87a3bd052
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
node_modules/
|
||||||
@ -14,7 +14,7 @@ RUN npm install
|
|||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Expose the MQTT port
|
# Expose the MQTT port
|
||||||
EXPOSE 1883
|
EXPOSE 3000 1883 8888
|
||||||
|
|
||||||
# Run the MQTT broker
|
# Run the MQTT broker
|
||||||
CMD ["node", "broker.js"]
|
CMD ["node", "index.js"]
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
npm install aedes --save
|
npm install aedes --save
|
||||||
npm install aedes-cli --global
|
npm install aedes-cli --global
|
||||||
|
npm install express aedes ws
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -23,3 +25,7 @@ aedes.on('publish', function (packet, client) {
|
|||||||
console.log('Published:', packet.payload.toString());
|
console.log('Published:', packet.payload.toString());
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
mosquitto_pub -h localhost -p 1883 -t test-sub -m "Server Push"
|
||||||
|
|
||||||
|
mosquitto_pub -h localhost -p 1883 -t test-sub -m "Server Push" -u "test_user" -P "test_pass"
|
||||||
14
docker-compose.yaml
Normal file
14
docker-compose.yaml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
node-server:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
- "1883:1883"
|
||||||
|
- "8888:8888"
|
||||||
|
tty: true
|
||||||
|
volumes:
|
||||||
|
- .:/usr/src/app
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=development
|
||||||
17
documents/web-api.yml
Normal file
17
documents/web-api.yml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
openapi: "3.0.2"
|
||||||
|
info:
|
||||||
|
title: WEB API
|
||||||
|
version: "1.0"
|
||||||
|
servers:
|
||||||
|
- url: http://localhost:8888
|
||||||
|
paths:
|
||||||
|
/helloworld:
|
||||||
|
get:
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
/timeout:
|
||||||
|
get:
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
2701
package-lock.json
generated
Normal file
2701
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
24
package.json
Normal file
24
package.json
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "npm-mqtt-server-mock",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "npm install aedes --save\r npm install aedes-cli --global",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://appj.pglikers.com/gitbucket/git/mock/npm-mqtt-server-mock.git"
|
||||||
|
},
|
||||||
|
"author": "ry.yamafuji",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"aedes": "^0.51.2",
|
||||||
|
"aedes-persistence": "^9.1.2",
|
||||||
|
"aedes-persistence-level": "^8.0.1",
|
||||||
|
"express": "^4.19.2",
|
||||||
|
"mqemitter": "^6.0.0",
|
||||||
|
"mqtt": "^5.7.0",
|
||||||
|
"ws": "^8.17.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/client.js
Normal file
24
src/client.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
const mqtt = require('mqtt');
|
||||||
|
|
||||||
|
const PUB_TOPIC = "test-sub";
|
||||||
|
const MESSAGE = "Message from server";
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
clientId: 'test_device2',
|
||||||
|
username: 'test_user',
|
||||||
|
password: 'test_pass',
|
||||||
|
};
|
||||||
|
|
||||||
|
const client = mqtt.connect('mqtt://localhost:1883', options);
|
||||||
|
|
||||||
|
client.on('connect', function () {
|
||||||
|
console.log('Connected to MQTT broker');
|
||||||
|
setInterval(function () {
|
||||||
|
client.publish(PUB_TOPIC, MESSAGE);
|
||||||
|
console.log(`Published: ${MESSAGE} to ${PUB_TOPIC}`);
|
||||||
|
}, 10000); // 30秒ごとにパブリッシュ
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on('error', function (err) {
|
||||||
|
console.error('MQTT client error:', err);
|
||||||
|
});
|
||||||
80
src/index.js
Normal file
80
src/index.js
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
// index.js
|
||||||
|
const http = require('http');
|
||||||
|
const aedes = require('aedes')({
|
||||||
|
connectTimeout: 1000 * 60 * 2
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const net = require('net');
|
||||||
|
const common = require('./lib/common'); //CommonJS
|
||||||
|
// import common from './lib/common'; //ESモジュール
|
||||||
|
const MQTT_PORT = 1883;
|
||||||
|
|
||||||
|
|
||||||
|
const mqttServer = net.createServer(aedes.handle);
|
||||||
|
mqttServer.listen(MQTT_PORT, () => {
|
||||||
|
common.logger(`Mocke MQTTerver Starting port ${MQTT_PORT}... [${common.toJaTimeFormat(new Date(), "YYYY-MM-DD hh:nn:ss")}]`);
|
||||||
|
});
|
||||||
|
|
||||||
|
const PUB_TOPIC = "test/sub";
|
||||||
|
const MESSAGE = "Message from server";
|
||||||
|
|
||||||
|
aedes.on('client', function (client) {
|
||||||
|
console.log('Client Connected: ', client.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
aedes.on('clientDisconnect', function (client) {
|
||||||
|
console.log('Client Disconnected: ', client.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
aedes.on('publish', function (packet, client) {
|
||||||
|
console.log('Message Published: ', packet.payload.toString());
|
||||||
|
console.log('Topic: ', packet.topic.toString());
|
||||||
|
});
|
||||||
|
|
||||||
|
// クライアント接続前に認証を行う
|
||||||
|
aedes.authenticate = function (client, username, password, callback) {
|
||||||
|
if ((username !== 'test_user' && username !== 'test_user_pass') || password.toString() !== 'test_pass') {
|
||||||
|
const error = new Error('Authentication failed');
|
||||||
|
error.returnCode = 4; // 認証エラー
|
||||||
|
callback(error, false);
|
||||||
|
} else if ((client.id !== 'test' && client.id !== 'test_device' && client.id !== 'test_device2')) {
|
||||||
|
const error = new Error('Client ID banned');
|
||||||
|
callback(error, false);
|
||||||
|
} else {
|
||||||
|
callback(null, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// クライアント接続時に特定のクライアントIDを拒否する
|
||||||
|
aedes.authorizePublish = function (client, packet, callback) {
|
||||||
|
common.logger(`authorizePublish ${client.id}`)
|
||||||
|
if (client.id !== 'test_device' && client.id !== 'test_device2') {
|
||||||
|
common.error("authorizePublish Failer")
|
||||||
|
const error = new Error('Client not authorized');
|
||||||
|
callback(error);
|
||||||
|
} else {
|
||||||
|
callback(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const httpserver = http.createServer()
|
||||||
|
|
||||||
|
/* httpサーバー APIより受付*/
|
||||||
|
common.logger(`Web Mocke APIServer Starting... [${common.toJaTimeFormat(new Date(), "YYYY-MM-DD hh:nn:ss")}]`);
|
||||||
|
httpserver.on('request', async (req, res) => {
|
||||||
|
|
||||||
|
if (req.url === '/helloworld') {
|
||||||
|
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
||||||
|
res.end('Hello World');
|
||||||
|
} else if (req.url === '/timeout') {
|
||||||
|
// 応答をまったく返さないことでクライアントにタイムアウトを引き起こす
|
||||||
|
common.logger('Timeout endpoint was hit, not sending response.');
|
||||||
|
} else {
|
||||||
|
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
||||||
|
res.end('Not Found');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
httpserver.listen(8888, '0.0.0.0');
|
||||||
72
src/lib/common.js
Normal file
72
src/lib/common.js
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/**
|
||||||
|
* common.ts
|
||||||
|
* 汎用的な関数を設置
|
||||||
|
*
|
||||||
|
* @module
|
||||||
|
*/
|
||||||
|
|
||||||
|
const common = {
|
||||||
|
/**
|
||||||
|
* ログを出力する(ログレベルinfo)
|
||||||
|
*
|
||||||
|
* @method logger
|
||||||
|
* @param message ログ出力内容
|
||||||
|
*/
|
||||||
|
logger: (message, ...optionalParams) => {
|
||||||
|
console.log(message, ...optionalParams);
|
||||||
|
// logger.info(message);
|
||||||
|
},
|
||||||
|
debug: (message, ...optionalParams) => {
|
||||||
|
console.debug(message, ...optionalParams);
|
||||||
|
// logger.debug(message);
|
||||||
|
},
|
||||||
|
error: (message, ...optionalParams) => {
|
||||||
|
console.error(message, ...optionalParams);
|
||||||
|
// logger.error(message);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日付修正 OCPP(UTC)からDB用に変換(JTS)
|
||||||
|
* UTCの時間を日本時間に変換する(+9)
|
||||||
|
* - prismaにrecordを更新する時の調整に使用
|
||||||
|
* - OCPPの仕様ではUTC時間で通信をおこなう
|
||||||
|
* @method toJaTimeString
|
||||||
|
* @param dt 日付UTC
|
||||||
|
* @returns {string} DB(JTS)
|
||||||
|
*/
|
||||||
|
toJaTimeString: (dt) => {
|
||||||
|
dt.setHours(dt.getHours() + 9)
|
||||||
|
return dt.toISOString()
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* toJaTimeFormat 日付フォーマット
|
||||||
|
* 日付を指定の形で整形する
|
||||||
|
* @method toJaTimeFormat
|
||||||
|
* @param {Date} dt 日付
|
||||||
|
* @param {string} format 整形(YYなどで指定する)
|
||||||
|
* @returns {string} 整形された文字列
|
||||||
|
*/
|
||||||
|
toJaTimeFormat: (dt, format = "") => {
|
||||||
|
dt = new Date(dt)
|
||||||
|
dt.setHours(dt.getHours() + 9)
|
||||||
|
const y = dt.getFullYear().toString();
|
||||||
|
const m = ('00' + (dt.getMonth() + 1)).slice(-2);
|
||||||
|
const d = ('00' + dt.getDate()).slice(-2);
|
||||||
|
const h = ('00' + dt.getHours()).slice(-2);
|
||||||
|
const n = ('00' + dt.getMinutes()).slice(-2);
|
||||||
|
const s = ('00' + dt.getSeconds()).slice(-2);
|
||||||
|
format = format.replace(/YYYY/, y);
|
||||||
|
format = format.replace(/MM/, m);
|
||||||
|
format = format.replace(/DD/, d);
|
||||||
|
format = format.replace(/hh/, h);
|
||||||
|
format = format.replace(/nn/, n);
|
||||||
|
format = format.replace(/ss/, s);
|
||||||
|
return format
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// export default common;
|
||||||
|
module.exports = common;
|
||||||
Loading…
x
Reference in New Issue
Block a user