Getting an error when subscribing a queue - node.js

My backend pushes messages to rabbitmq queue and I need to fetch those messages to display in the frontend part of the messages, since the messages have to be in specific order, I cannot use an asynchronous approach.
I have written this code
var open require("amqplib").connect("amqp://guest:guest#localhost:5682");
var queue = "developer";
export default {
name: 'Subsriber',
data: function() {
return {
selected: "",
services: [],
}
},
mounted() {
var url = "http://10.0.9.134:5060/services/scripts";
this.services = []; // empty the existing list first.
setTimeout(() => {
axios.get(url)
.then(response => {
this.services = response.data;
})
}, 2000)
open.then(function(conn){
return conn.createChannel();
}).then(function(ch){
return ch.assertQueue(queue).then(function(ok){
return ch.consume(queue, function(msg){
if (msg != null){
console.log(msg.content.toString());
}
});
});
});
}
but I get this error:
"Unhandled rejection TypeError: QS.unescape is not a function
openFrames#webpack-internal:///./node_modules/_amqplib#0.5.2#amqplib/lib/connect.js:50:1
connect#webpack-internal:///./node_modules/_amqplib#0.5.2#amqplib/lib/connect.js:145:14
connect/<#webpack-internal:///./node_modules/_amqplib#0.5.2#amqplib/channel_api.js:7:12
connect#webpack-internal:///./node_modules/_amqplib#0.5.2#amqplib/channel_api.js:6:10
#webpack-internal:///./node_modules/babel-loader/lib/index.js!./node_modules/vue-loader/lib/selector.js?type=script&index=0!./src/components/SelectServices.vue:56:12
["./node_modules/babel-loader/lib/index.js!./node_modules/vue-loader/lib/selector.js?type=script&index=0!./src/components/SelectServices.vue"]#http://10.0.9.134/app.js:1251:1
__webpack_require__#http://10.0.9.134/app.js:679:1
hotCreateRequire/fn#http://10.0.9.134/app.js:89:20
#webpack-internal:///./src/components/SelectServices.vue:1:148
["./src/components/SelectServices.vue"]#http://10.0.9.134/app.js:1804:1
__webpack_require__#http://10.0.9.134/app.js:679:1
hotCreateRequire/fn#http://10.0.9.134/app.js:89:20
#webpack-internal:///./src/router/index.js:4:85
["./src/router/index.js"]#http://10.0.9.134/app.js:1820:1
__webpack_require__#http://10.0.9.134/app.js:679:1
hotCreateRequire/fn#http://10.0.9.134/app.js:89:20
#webpack-internal:///./src/main.js:4:66
["./src/main.js"]#http://10.0.9.134/app.js:1812:1
__webpack_require__#http://10.0.9.134/app.js:679:1
hotCreateRequire/fn#http://10.9.0.134/app.js:89:20
[0]#http://10.9.1.147/app.js:1829:18
__webpack_require__#http://10.0.9.134/app.js:679:1
#http://10.9.0.134/app.js:725:18
#http://10.9.0.134/app.js:1:1"

Related

Push notification shows object Object even though i am setting the right value

I am trying to implement push notifications with react and nodejs using service workers.
I am having problem while i am showing notification to the user.
Here is my service worker code:
self.addEventListener('push', async (event) => {
const {
type,
title,
body,
data: { redirectUrl },
} = event.data.json()
if (type === 'NEW_MESSAGE') {
try {
// Get all opened windows that service worker controls.
event.waitUntil(
self.clients.matchAll().then((clients) => {
// Get windows matching the url of the message's coming address.
const filteredClients = clients.filter((client) => client.url.includes(redirectUrl))
// If user's not on the same window as the message's coming address or if it window exists but it's, hidden send notification.
if (
filteredClients.length === 0 ||
(filteredClients.length > 0 &&
filteredClients.every((client) => client.visibilityState === 'hidden'))
) {
self.registration.showNotification({
title,
options: { body },
})
}
}),
)
} catch (error) {
console.error('Error while fetching clients:', error.message)
}
}
})
self.addEventListener('notificationclick', (event) => {
event.notification.close()
console.log(event)
if (event.action === 'NEW_MESSAGE') {
event.waitUntil(
self.clients.matchAll().then((clients) => {
if (clients.openWindow) {
clients
.openWindow(event.notification.data.redirectUrl)
.then((client) => (client ? client.focus() : null))
}
}),
)
}
})
When new notification comes from backend with a type of 'NEW_MESSAGE', i get the right values out of e.data and try to use them on showNotification function but it seems like something is not working out properly because notification looks like this even though event.data equals to this => type = 'NEW_MESSAGE', title: 'New Message', body: , data: { redirectUrl: }
Here is how notification looks:
Thanks for your help in advance.
The problem was i assigned parameters in the wrong way.
It should've been like this:
self.registration.showNotification(title, { body })

How to make kuzzle-device-manager plugin API actions works?

I successfully installed and loaded kuzzle-device-manager in the backend file:
import { Backend } from 'kuzzle';
import { DeviceManagerPlugin } from 'kuzzle-device-manager';
const app = new Backend('playground');
console.log(app.config);
const deviceManager = new DeviceManagerPlugin();
const mappings = {
updatedAt: { type: 'date' },
payloadUuid: { type: 'keyword' },
value: { type: 'float' }
}
deviceManager.devices.registerMeasure('humidity', mappings)
app.plugin.use(deviceManager)
app.start()
.then(async () => {
// Interact with Kuzzle API to create a new index if it does not already exist
console.log(' started!');
})
.catch(console.error);
But when i try to use controllers from that plugin for example device-manager/device with create action i get an error output.
Here is my "client" code in js:
const { Kuzzle, WebSocket } = require("kuzzle-sdk")
const kuzzle = new Kuzzle(
new WebSocket('KUZZLE_IP')
)
kuzzle.on('networkError', error => {
console.error('Network Error: ', error);
})
const run = async () => {
try {
// Connects to the Kuzzle server
await kuzzle.connect();
// Creates an index
const result = await kuzzle.query({
index: "nyc-open-data",
controller: "device-manager/device",
action: "create",
body: {
model: "model-1234",
reference: "reference-1234"
}
}, {
queuable: false
})
console.log(result)
} catch (error) {
console.error(error.message);
} finally {
kuzzle.disconnect();
}
};
run();
And the result log:
API action "device-manager/device":"create" not found
Note: The nyc-open-data index exists and is empty.
We apologize for this mistake in the documentation, the device-manager/device:create method is not available because the plugin is using auto-provisioning until the v2.
You should send a payload to your decoder, the plugin will automatically provision the device if it does not exists https://docs.kuzzle.io/official-plugins/device-manager/1/guides/decoders/#receive-payloads

Unable to use ActiveMQ priority messages using STOMP protocol in nodejs

I have an application which sends messages to a queue, and another application which subscribes to the queue and process it. I want OTP messages to be given higher priority than other messages, hence I am trying to use ActiveMQ message priority to achieve this.
This is the code for ActiveMQ connection using STOMP protocol in nodejs using stompit library:
const serverPrimary = {
host: keys.activeMQ.host,
port: keys.activeMQ.port,
ssl: ssl,
connectHeaders: {
host: '/',
login: keys.activeMQ.username,
passcode: keys.activeMQ.password,
'heart-beat': '5000,5000',
},
}
connManager = new stompit.ConnectFailover(
[serverPrimary, serverFailover],
reconnectOptions,
)
connManager.on('error', function (e) {
const connectArgs = e.connectArgs
const address = connectArgs.host + ':' + connectArgs.port
logger.error({ error: e, customMessage: address })
})
channelPool = new stompit.ChannelPool(connManager)
Code for sending message
const pushMessageToAMQ = (queue, message) => {
const queues = Object.values(activeMQ.queues)
if (!queues.includes(queue)) {
_mqLog(mqLogMessages.unknownQueue + queue)
return
}
//Priority header is set
const header = {
destination: queue,
priority: 7
}
//If message is not a string
if (typeof message !== 'string') message = JSON.stringify(message)
//Logging message before sending
_mqLog(
mqLogMessages.sending,
{ service: services.amq },
{ header: header, message: message },
)
//Sending message to amq
_sendMessageToAMQ(header, message, error => {
if (error) {
_mqError(error, mqLogMessages.sendingError, { service: services.amq })
}
})
}
const _sendMessageToAMQ = (headers, body, callback) => {
channelPool.channel((error, channel) => {
if (error) {
callback(error)
return
}
channel.send(headers, body, callback)
})
}
Here's the code for subscribing to queue in the second application:
const amqSubscribe = (queue, callback, ack = 'client-individual') => {
log({ customMessage: 'Subscribing to ' + queue })
const queues = Object.values(activeMQ.queues)
if (!queues.includes(queue)) {
return
}
channelPool.channel((error, channel) => {
let header = {
destination: queue,
ack: ack,
'activemq.prefetchSize': 1,
}
//Check for error
if (error) {
_mqError(error, mqLogMessages.baseError, header)
} else {
channel.subscribe(
header,
_synchronisedHandler((error, message, next) => {
//Check for error
if (error) {
_mqError(error, mqLogMessages.subscriptionError, header)
next()
} else {
//Read message
message.readString('utf-8', function (error, body) {
if (error) {
_mqError(error, mqLogMessages.readError, header)
next()
} else {
//Message read successfully call callback
callback(body, () => {
//Acknowledgment callback
channel.ack(message)
next()
})
}
})
}
}),
)
}
})
}
Activemq.xml
<policyEntries>
<policyEntry queue=">" prioritizedMessages="true" useCache="false" expireMessagesPeriod="0" queuePrefetch="1" />
.......
I tried pushing different messages with different priority and turned on the second application (i.e. the one which subscribes to the messages) after all the messages were pushed to queue. However, the execution order of the messages was the same as the one which was sent. The priority didn't change anything. Is there something that I am missing?
Do I have to add something in consumer end for it to work?
Support for priority is disabled by default in ActiveMQ "Classic" (used by Amazon MQ). As the documentation states:
...support [for message priority] is disabled by default so it needs to be be enabled using per destination policies through xml configuration...
You need to set prioritizedMessages="true" in the policyEntry for your queue, e.g.:
<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry queue=">" prioritizedMessages="true"/>
...
To be clear, this is configured on the broker (i.e. not the client) in activemq.xml, and it applies to every kind of client.

Mock multiple api call inside one function using Moxios

I am writing a test case for my service class. I want to mock multiple calls inside one function as I am making two API calls from one function. I tried following but it is not working
it('should get store info', async done => {
const store: any = DealersAPIFixture.generateStoreInfo();
moxios.wait(() => {
const request = moxios.requests.mostRecent();
request.respondWith({
status: 200,
response: store
});
const nextRequest = moxios.requests.at(1);
nextRequest.respondWith({
status: 200,
response: DealersAPIFixture.generateLocation()
});
});
const params = {
dealerId: store.dealerId,
storeId: store.storeId,
uid: 'h0pw1p20'
};
return DealerServices.retrieveStoreInfo(params).then((data: IStore) => {
const expectedOutput = DealersFixture.generateStoreInfo(data);
expect(data).toMatchObject(expectedOutput);
});
});
const nextRequest is always undefined
it throw error TypeError: Cannot read property 'respondWith' of undefined
here is my service class
static async retrieveStoreInfo(
queryParam: IStoreQueryString
): Promise<IStore> {
const res = await request(getDealerStoreParams(queryParam));
try {
const locationResponse = await graphQlRequest({
query: locationQuery,
variables: { storeId: res.data.storeId }
});
res.data['inventoryLocationCode'] =
locationResponse.data?.location?.inventoryLocationCode;
} catch (e) {
res.data['inventoryLocationCode'] = 'N/A';
}
return res.data;
}
Late for the party, but I had to resolve this same problem just today.
My (not ideal) solution is to use moxios.stubRequest for each request except for the last one. This solution is based on the fact that moxios.stubRequest pushes requests to moxios.requests, so, you'll be able to analyze all requests after responding to the last call.
The code will look something like this (considering you have 3 requests to do):
moxios.stubRequest("get-dealer-store-params", {
status: 200,
response: {
name: "Audi",
location: "Berlin",
}
});
moxios.stubRequest("graph-ql-request", {
status: 204,
});
moxios.wait(() => {
const lastRequest = moxios.requests.mostRecent();
lastRequest.respondWith({
status: 200,
response: {
isEverythingWentFine: true,
},
});
// Here you can analyze any request you want
// Assert getDealerStoreParams's request
const dealerStoreParamsRequest = moxios.requests.first();
expect(dealerStoreParamsRequest.config.headers.Accept).toBe("application/x-www-form-urlencoded");
// Assert graphQlRequest
const graphQlRequest = moxios.requests.get("POST", "graph-ql-request");
...
// Assert last request
expect(lastRequest.config.url).toBe("status");
});

NodeJS VM2 proper way to access console when set to 'redirect'

I'm using the VM2 package to run user code. I'm trying to intercept console output and have set the NodeVM object's console property to 'redirect':
// Create a new sandbox VM for this request
const vm = new NodeVM( {
console: 'redirect',
timeout: 30000,
sandbox: { request, state, response },
require: {
external: true
}
});
According to the documentation that redirects console output to 'events'. I'm new to NodeJS, how do I hook into those events to capture the console.log messages executed inside the Sandbox?
After digging through the source code, I found this file where the event emit is occuring:
sandbox.js
if (vm.options.console === 'inherit') {
global.console = Contextify.readonly(host.console);
} else if (vm.options.console === 'redirect') {
global.console = {
log(...args) {
vm.emit('console.log', ...Decontextify.arguments(args));
return null;
},
info(...args) {
vm.emit('console.info', ...Decontextify.arguments(args));
return null;
},
warn(...args) {
vm.emit('console.warn', ...Decontextify.arguments(args));
return null;
},
error(...args) {
vm.emit('console.error', ...Decontextify.arguments(args));
return null;
},
dir(...args) {
vm.emit('console.dir', ...Decontextify.arguments(args));
return null;
},
time: () => {},
timeEnd: () => {},
trace(...args) {
vm.emit('console.trace', ...Decontextify.arguments(args));
return null;
}
};
}
All you need to do to listen to these events is to bind an event listener on the vm you've created:
// Create a new sandbox VM for this request
const vm = new NodeVM( {
console: 'redirect',
require: {
external: ['request']
}
});
vm.on('console.log', (data) => {
console.log(`VM stdout: ${data}`);
});
Likewise, you can bind to console.log, console.info, console.warn, console.error, console.dir, and console.trace. Hopefully this will save someone else some time.

Resources