amplify-appsync-simulator
Version:
An AppSync Simulator to test AppSync API.
203 lines • 6.75 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MQTTServer = void 0;
const mqtt_connection_1 = __importDefault(require("mqtt-connection"));
const ws_1 = __importDefault(require("ws"));
const steed_1 = __importDefault(require("steed"));
const pino_1 = __importDefault(require("pino"));
const lodash_1 = require("lodash");
const nanoid_1 = require("nanoid");
const trie_listener_1 = require("./trie-listener");
const client_1 = require("./client");
const events_1 = require("events");
const DEFAULT_OPTIONS = {
maxConnections: 10000000,
backend: {
wildcardOne: '+',
wildcardSome: '#',
},
stats: false,
publishNewClient: true,
publishClientDisconnect: true,
publishSubscriptions: true,
maxInflightMessages: 1024,
onQoS2publish: 'noack',
logger: {
name: 'amplify-mqtt-server',
level: 'warn',
},
};
const nop = () => { };
class MQTTServer extends events_1.EventEmitter {
constructor(options = {}, callback = (err, data) => { }) {
super();
this.callback = callback;
this.options = (0, lodash_1.defaultsDeep)(options, DEFAULT_OPTIONS);
this._dedupId = 0;
this.clients = {};
this.closed = false;
this.closed = false;
this.logger = (0, pino_1.default)(this.options.logger);
this.onQoS2publish = this.options.onQoS2publish;
this.id = this.options.id || (0, nanoid_1.nanoid)(7);
new Promise(resolve => {
const listener = new trie_listener_1.TrieListener(this.options.backend);
listener.once('ready', function () {
resolve(listener);
});
})
.then(listener => {
this.listener = listener;
this.init();
})
.catch(err => {
callback(err);
});
}
init() {
this.on('clientConnected', client => {
if (this.options.publishNewClient) {
this.publish({
topic: `$SYS/${this.id}/new/clients`,
payload: client.id,
});
}
this.clients[client.id] = client;
});
this.once('ready', () => {
this.callback(null, this);
});
this.on('ready', () => {
this.listener.subscribe('$SYS/+/new/clients', (topic, payload) => {
const serverId = topic.split('/')[1];
const clientId = payload;
if (this.clients[clientId] && serverId !== this.id) {
this.clients[clientId].close(null, 'new connection request');
}
});
});
if (this.options.publishSubscriptions) {
this.on('subscribed', (topic, client) => {
this.publish({
topic: `$SYS/${this.id}/new/subscribes`,
payload: JSON.stringify({
clientId: client.id,
topic: topic,
}),
});
});
this.on('unsubscribed', (topic, client) => {
this.publish({
topic: '$SYS/' + this.id + '/new/unsubscribes',
payload: JSON.stringify({
clientId: client.id,
topic: topic,
}),
});
});
}
this.on('clientDisconnected', client => {
if (this.options.publishClientDisconnect) {
this.publish({
topic: '$SYS/' + this.id + '/disconnect/clients',
payload: client.id,
});
}
delete this.clients[client.id];
});
}
toString() {
return 'AmplifyMQTTServer.Server';
}
subscribe(topic, callback, done) {
this.listener.subscribe(topic, callback, done);
}
publish(packet, client, callback) {
let logger = this.logger;
if (typeof client === 'function') {
callback = client;
client = null;
}
else if (client) {
logger = client.logger;
}
if (!callback) {
callback = nop;
}
const newPacket = {
topic: packet.topic,
payload: packet.payload,
messageId: (0, nanoid_1.nanoid)(7),
qos: packet.qos,
retain: packet.retain,
};
const opts = {
qos: packet.qos,
messageId: newPacket.messageId,
};
if (client) {
opts.clientId = client.id;
}
if (this.closed) {
logger.debug({ packet: newPacket }, 'not delivering because we are closed');
return;
}
this.listener.publish(newPacket.topic, newPacket.payload, opts, () => {
if (newPacket.topic.indexOf('$SYS') >= 0) {
logger.trace({ packet: newPacket }, 'published packet');
}
else {
logger.debug({ packet: newPacket }, 'published packet');
}
this.emit('published', newPacket, client);
callback(undefined, newPacket);
});
}
close(callback = nop) {
const stuffToClose = [];
if (this.closed) {
return callback();
}
this.closed = true;
Object.keys(this.clients).forEach(i => {
stuffToClose.push(this.clients[i]);
});
steed_1.default.each(stuffToClose, (toClose, cb) => {
try {
toClose.close(cb, 'server closed');
}
catch (e) { }
}, () => {
this.listener.close(() => {
this.logger.info('server closed');
this.emit('closed');
callback();
});
});
}
updateOfflinePacket(client, originMessageId, packet, callback) {
if (callback) {
callback(null, packet);
}
}
attachHttpServer(server, path) {
const opt = { server: server };
if (path) {
opt.path = path;
}
const wss = new ws_1.default.Server(opt);
wss.on('connection', socket => {
const stream = ws_1.default.createWebSocketStream(socket, {});
const conn = new mqtt_connection_1.default(stream);
new client_1.Client(conn, this);
});
}
nextDedupId() {
return this._dedupId++;
}
}
exports.MQTTServer = MQTTServer;
//# sourceMappingURL=server.js.map