mqtt-forget
Version:
Command line tool to remove retained MQTT topics by wildcard
144 lines (130 loc) • 3.3 kB
JavaScript
const async = require('async');
const Mqtt = require('mqtt');
const Confirm = require('prompt-confirm');
const yargs = require('yargs')
.option('d', {
alias: 'debug',
describe: 'Enable debug messages'
})
.option('t', {
alias: 'topic',
demandOption: true,
describe: 'MQTT topic, wildcards + and # allowed, may be repeated'
})
.option('u', {
alias: 'url',
default: 'mqtt://127.0.0.1',
describe: 'MQTT broker url'
})
.option('f', {
alias: 'force',
describe: 'Remove topics without confirmation'
})
.usage('Usage: $0 <options>')
.help()
.version()
.argv;
if (typeof yargs.topic === 'string') {
yargs.topic = [yargs.topic];
}
let debug;
const {log} = console;
if (yargs.debug) {
debug = log;
} else {
debug = () => {};
}
const topics = [];
let wildcard = false;
let subscriptions = 0;
let retainTimer;
let ready = false;
debug('connect', yargs.url);
const mqtt = Mqtt.connect(yargs.url, {
connectTimeout: 5000
});
function remove(topic, callback) {
mqtt.publish(topic, '', {retain: true}, err => {
if (err) {
console.error('publish error', err.message);
callback();
} else {
log('removed topic', topic);
callback();
}
});
}
function main() {
const queue = [];
ready = true;
log('found', topics.length, 'retained topic' + (topics.length === 1 ? '' : 's'));
topics.forEach(topic => {
queue.push(cb => {
if (yargs.force) {
remove(topic, cb);
} else {
const prompt = new Confirm('really remove ' + topic + ' ?');
prompt.ask(answer => {
if (answer) {
remove(topic, cb);
} else {
cb();
}
});
}
});
});
async.series(queue, () => {
setTimeout(() => {
mqtt.end(false, () => {
process.exit(0);
});
}, 600);
});
}
function timer() {
if (!ready) {
clearTimeout(retainTimer);
if (!wildcard && topics.length === subscriptions) {
main();
} else {
retainTimer = setTimeout(() => {
main();
}, 1200);
}
}
}
mqtt.on('connect', () => {
debug('mqtt connect');
yargs.topic.forEach(topic => {
if (topic.match(/[+#]/)) {
wildcard = true;
} else {
subscriptions += 1;
}
mqtt.subscribe(topic, err => {
if (err) {
console.error('subscribe error', err.message, topic);
} else {
debug('subscribed', topic);
}
});
});
timer();
});
mqtt.on('offline', err => {
console.error('mqtt connection error', err && err.message);
process.exit(1);
});
mqtt.on('error', err => {
console.error('mqtt connection error', err && err.message);
process.exit(1);
});
mqtt.on('message', (topic, message, packet) => {
if (packet.retain && !ready) {
debug('<', topic);
topics.push(topic);
timer();
}
});