256 lines
8.4 KiB
JavaScript
256 lines
8.4 KiB
JavaScript
import yargs from 'yargs/yargs'
|
|
import { hideBin } from 'yargs/helpers'
|
|
import fs from 'fs'
|
|
import {RedisConnexion} from '../redisConnexion.js'
|
|
import riConfig from './riConfig.json' with { type: 'json' }
|
|
import pkg from 'enquirer';
|
|
const { prompt } = pkg;
|
|
|
|
|
|
const dialogData = {
|
|
'step1' : {
|
|
'question': {
|
|
'type': 'input',
|
|
'name': 'uid',
|
|
'message': 'Sender uid ? (Back-ends: backend-marklogic / backend-smed )'
|
|
},
|
|
'nextStep': 'step2'
|
|
},
|
|
'step2' : {
|
|
'question': {
|
|
'type': 'autocomplete',
|
|
'name': 'channel',
|
|
'message': 'Channel ?',
|
|
'limit': 10,
|
|
'initial': 2,
|
|
'choices': [
|
|
'[NEW]',
|
|
'dataSync:userRoles',
|
|
'system:notifs',
|
|
'infraNotifs:httpGateway',
|
|
'infraNotifs:midas',
|
|
'services:notifications',
|
|
'services:pdfs',
|
|
]
|
|
},
|
|
'nextStep': 'step3'
|
|
},
|
|
'step3': {
|
|
'question': {
|
|
'type': 'select',
|
|
'name': 'type',
|
|
'message': 'Type of message ?',
|
|
'choices': [
|
|
{ 'message': 'Event', 'value': 'event' },
|
|
{ 'message': 'Action', 'value': 'action' },
|
|
{ 'message': 'Other', 'value': 'other' },
|
|
]
|
|
},
|
|
'nextStep': 'step4-{{type}}'
|
|
},
|
|
'step4-event': {
|
|
'question': {
|
|
'type': 'select',
|
|
'name': 'eventType',
|
|
'message': 'Type of event ?',
|
|
'choices': null,
|
|
},
|
|
'nextStep': 'step5'
|
|
},
|
|
'step4-action': {
|
|
'question': {
|
|
'type': 'select',
|
|
'name': 'action',
|
|
'message': 'Type of action ?',
|
|
'choices': null
|
|
},
|
|
'nextStep': 'step5'
|
|
},
|
|
'step4-other': {
|
|
'question': {
|
|
'type': 'input',
|
|
'name': 'payload',
|
|
'message': 'Payload (json)'
|
|
},
|
|
'nextStep': 'step6'
|
|
},
|
|
'step5': {
|
|
'question': {
|
|
'type': 'input',
|
|
'name': 'payload',
|
|
'message': 'Payload (json), [enter for none]'
|
|
},
|
|
'nextStep': 'step6'
|
|
},
|
|
'step6': {
|
|
'question': {
|
|
'type': 'select',
|
|
'name': 'confirm',
|
|
'message': 'Confirm what you want:',
|
|
'initial': 'send',
|
|
'choices': [
|
|
{ 'message': 'Send on the bus', 'value': 'send' },
|
|
{ 'message': 'Save to file', 'value': 'save' },
|
|
{ 'message': 'Cancel', 'value': 'cancel' },
|
|
]
|
|
},
|
|
'nextStep': null
|
|
},
|
|
}
|
|
|
|
const selectors = {
|
|
'chan2eventTypes': {
|
|
'dataSync:userRoles': ['updated'],
|
|
'system:notifs': ['growl'],
|
|
},
|
|
'chan2actions': {
|
|
'infraNotifs:httpGateway': ['TIME', 'RELOADACCESSRIGHTS', 'GETACCESSRIGHTS'],
|
|
'infraNotifs:midas': ['TIME', 'LISTPLUGINS', 'RELOADPLUGINS'],
|
|
'services:notifications': [ 'notify' ],
|
|
}
|
|
}
|
|
|
|
|
|
class Dialog {
|
|
|
|
constructor(dialogData, selectors){
|
|
this.dialogData = dialogData
|
|
this.selectors = selectors
|
|
this.curStep = null
|
|
this.answers = {}
|
|
}
|
|
|
|
async start(step){
|
|
this.curStep = step
|
|
while(this.curStep && this.dialogData[this.curStep]){
|
|
let latestAnswer = await(this.askStep(this.curStep))
|
|
if(latestAnswer[this.dialogData[this.curStep].question.name]=='[NEW]'){
|
|
latestAnswer = await prompt({
|
|
'type': 'input',
|
|
'name': this.dialogData[this.curStep].question.name,
|
|
'message': `(enter your new/custom value) ${this.dialogData[this.curStep].question.message}`,
|
|
})
|
|
}
|
|
|
|
this.curStep = this.dialogData[this.curStep].nextStep
|
|
Object.assign(this.answers, latestAnswer)
|
|
|
|
if(this.curStep){
|
|
this.curStep = this.curStep.replace(/{{(\w+)}}/, (_, token) => (this.answers[token] || '' ) )
|
|
}
|
|
}
|
|
if(this.curStep) console.warn(`Stopped because cannot find step "${this.curStep}" !`)
|
|
return(this.answers)
|
|
}
|
|
|
|
async askStep(step){
|
|
// Fills empty selectors
|
|
let question = this.dialogData[step].question
|
|
if((question.type=='select') && (question.choices===null)){
|
|
switch(question.name){
|
|
case 'eventType':
|
|
question.choices = this.selectors.chan2eventTypes.hasOwnProperty(this.answers.channel)
|
|
? ['[NEW]', ...this.selectors.chan2eventTypes[this.answers.channel]]
|
|
: question.choices = ['[NEW]']
|
|
break
|
|
case 'action':
|
|
question.choices = this.selectors.chan2actions.hasOwnProperty(this.answers.channel)
|
|
? ['[NEW]', ...this.selectors.chan2actions[this.answers.channel]]
|
|
: question.choices = ['[NEW]']
|
|
break
|
|
default: question.choices = ['[NEW]']
|
|
}
|
|
}
|
|
return(await prompt(this.dialogData[step].question))
|
|
}
|
|
|
|
}
|
|
|
|
async function startRedis(midasConfig) {
|
|
let REDIScnx = new RedisConnexion({
|
|
debug: true,
|
|
config: midasConfig,
|
|
});
|
|
console.log('Starting REDIS...');
|
|
await REDIScnx.redisLogin();
|
|
console.log('REDIS Login OK');
|
|
return (REDIScnx);
|
|
}
|
|
|
|
async function inject(rediscnx, chan, packet){
|
|
await rediscnx.redisPublish(chan, packet)
|
|
}
|
|
|
|
|
|
async function batchInject(rediscnx, batch, delay=0){
|
|
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms))
|
|
|
|
for(let msg of batch){
|
|
if(msg.channel && msg.packet){
|
|
await rediscnx.redisPublish(msg.channel, msg.packet)
|
|
} else console.error('Bad message format, skipped !?', msg)
|
|
await sleep(delay)
|
|
}
|
|
}
|
|
|
|
const argv = yargs(hideBin(process.argv)).command('Rabbit-Injector', 'Injects messages on bus', {})
|
|
.options({
|
|
'file': {
|
|
description: 'Instead of asking question, directly inject from a .dmsg file',
|
|
alias: 'f',
|
|
type: 'string'
|
|
},
|
|
}).help().version('1.0').argv
|
|
|
|
if(argv.file){
|
|
let fileName = argv.file
|
|
if(!fileName.endsWith('.bmsg')) fileName+='.bmsg'
|
|
if(fs.existsSync(fileName)){
|
|
let fileData
|
|
try{
|
|
fileData = JSON.parse(fs.readFileSync(fileName))
|
|
} catch(err){
|
|
console.error('Bad json in file !?')
|
|
process.exit(1)
|
|
}
|
|
|
|
let rediscnx = await startRedis(riConfig)
|
|
if(Array.isArray(fileData)){
|
|
await batchInject(rediscnx, fileData)
|
|
} else {
|
|
if(Array.isArray(fileData.sequence)){
|
|
let batchIter = (parseInt(fileData.sequenceLoop)>1) ? parseInt(fileData.sequenceLoop) : 1
|
|
for(let i=0; i<batchIter; i++){
|
|
if(parseInt(fileData.sequenceDelay)>0) await batchInject(rediscnx, fileData.sequence, parseInt(fileData.sequenceDelay))
|
|
else await batchInject(rediscnx, fileData)
|
|
}
|
|
} else if(fileData.channel && fileData.packet){
|
|
await inject(rediscnx, fileData.channel, fileData.packet)
|
|
} else console.error('Bad file format !?', fileData)
|
|
}
|
|
await rediscnx.redisClient.disconnect()
|
|
} else { console.error('Cannot open file !')}
|
|
} else {
|
|
let dialog = new Dialog(dialogData, selectors)
|
|
dialog.start('step1').then(answers => {
|
|
let packet = {}
|
|
if(answers.type != 'other') packet[answers.type] = answers[answers.type]
|
|
packet.sender = answers.uid
|
|
packet.reqid = crypto.randomUUID()
|
|
if(answers.payload) packet.payload = answers.payload
|
|
|
|
if(answers.confirm=="send"){
|
|
inject(answers.channel, packet)
|
|
} else if(answers.confirm=="save"){
|
|
prompt({'type': 'input', 'name': 'filename', 'message': 'Filename ?'}).then(answer =>{
|
|
let fileName = answer.filename
|
|
if(!fileName.endsWith('.bmsg')) fileName+='.bmsg'
|
|
fs.writeFileSync(fileName, JSON.stringify({ channel: answers.channel, packet: packet}))
|
|
})
|
|
}
|
|
|
|
})
|
|
}
|
|
|
|
|