I'm creating an inactivity check for my bot where it sends a message to the user if X amount of minutes have passed since the last message he sent.
bot.dialog('SomeDialog',
function(session, args){
let text = "The text sent to the user";
session.send(text, session.message.text);
check(session); //The function where I send the session to do the checking
session.endDialog();
}
);
The check function is where the problem happens:
check(session){
if(!session.conversationData.talked){
session.conversationData.talked = 1;
}
}
When I run it, I always get
Cannot read property 'conversationData' of undefined
If I use session.conversationData.talked within the bot.dialog it works, but not on the check function.
What am I doing wrong here?
Your code snippet works fine on my side, maybe you can provide your whole picture of your porject for further analysis.
However, to your requirememnt, you can consider to use the node package botbuilder-timeout,
This could be an "async" timing issue. The session on your browser / server needs to be sync'd.
Is this JS server side, or browser side? And what framework is this intended for?
Related
I am trying to create an automation script (action launch point, trigger by a button on UI) for Maximo using javascript to do some data validation then show popup if there is invalid data.
I try to call service.setWarning() but the script still process instead of showing a warning message, if I do some UI interaction later, that warning message randomly display later.
Then I try the service.error() which should show an error message similar to the exception message in Maximo, the script does stop running but there is no popup message.
If I check systemError.log, I can see both the warning and error message displayed in the log?
So what is causing this and how can I make it behave correctly?
EDIT1: here is the script, I already setup the message in database configuration (messagegroup RFQ, messagekey 2VENDORS):
load("nashorn:mozilla_compat.js");
importPackage(Packages.psdi.security);
importPackage(Packages.psdi.mbo);
importPackage(Packages.psdi.server);
var mxServer = MXServer.getMXServer();
var userInfo = mxServer.getSystemUserInfo();
var rfqLineSet = mbo.getMboSet("RFQLINE");
var totalCost = 0;
var current_datetime = new Date();
var today = current_datetime.toISOString();
for(var currMbo=rfqLineSet.moveFirst(); currMbo!=null; currMbo=rfqLineSet.moveNext()) {
totalCost = totalCost + currMbo.getDouble("LINECOST");
}
if (totalCost < 50000) {
var rfqVendorSet = mbo.getMboSet("RFQVENDOR");
if (rfqVendorSet.count() > 2) {
service.error("RFQ","2VENDORS",null);
}
}
Maximo version 7.6.1
EDIT2: I tried the service.yncerror("RFQ","2VENDORS",null); which should display a yes/no error popup message but same issue, it only appears in the systemError.log
EDIT3: I did some tests and found out that if I write the code in Jython then the popup works but not in Javascript. How can this be?
UPDATE: I moved all my scripts to use python instead of javascript, seems that Maximo works best with automation script written in python.
Thanks.
"Warnings" in Maximo are some bits of data that just ride along with the MBO set. As a warning, they aren't supposed to stop execution, just let you know of something important, but they won't even do that on their own. You need to do something at some point to fetch the warnings from the set and display them. If you don't, Maximo will on its own for certain actions (usually for those actions that would include a warning Maximo itself added), but that probably isn't when you actually want it to be displayed. I have seen many people mix this up and not understand what these warnings are or how they actually work.
"Errors" are meant to be logic stopping messages. Something went wrong and the user needs to know about it before more logic runs. This sounds more like your use case. Errors are still meant to be a message to the user though, so you have to supply a message for the error method. You can't just put any string you want as your message in there though (well, you shouldn't) as that doesn't allow Maximo to translate the message or fill in message variables. It also means you have to change code whenever you want to change the message, instead of simply changing a configuration live. Instead you need to go to Database Configuration and add a new message in there. When you do that, you will create a message group and message key value for your message. Now when you call the error method, you will pass in that error group and error key as parameters. Maximo will take that, look it up in the message table and then display the message associated with that group and key for your configured language. It can also replace some special message variables at this time too, but that's a lesson for another time.
For example, you might go to Database Configuration and open the dialog for the messages and add a message of "The value you entered in the 'count' field is not a number. Please enter a number before continuing." and give it a message group of "MyCustomGrp" and a key of "NotANumber". Then in your code when you want to stop the code and display that message, you would call service.error("MyCustomGrp", "NotANumber").
The other potential problem you could be having is that you do need to be running the code that throws the error in some way attached to the interactive user session. Generally, that's a given, but there are some things you could be doing that would cause your code to run separate from that interactive user session. If you are seeing your error message in the logs, then you have set that part up correctly and it likely means your code is not part of the interactive user session. This is where knowing the rest of your code is very important.
I am trying to change the URL request on an already connected socket but I can't figure out how or if it is even possible.
I am working with the WebSocket API and CoinCap.
What I am doing right now is closing the connection and creating a new one with the new parameters.
// Create a new WS connection
const webSocketURL = `wss://ws.coincap.io/prices?assets=${loadedKeys}`
// loadedKeys could be a string of one coin (e.g. bitcoin) or an array
// or an array (e.g. bitcoin,ethereum,monero,litecoin), has to be dynamic.
pricesWs = new WebSocket(webSocketURL);
pricesWs.onopen = function () {
console.log(`conected: ${pricesWs.readyState}`)
}
pricesWs.onmessage = function (msg) {
handleUpdateCB(msg.data);
}
// then when I need to receive different coin prices
// I close the connection and reopen a new one.
anotherFunction() {
pricesWs.close();
pricesWs = new WebSocket(aNewWebSocketURL);
}
I tried sending parameters as messages with send() function without success, I keep receiving the same data, let's say I first connect asking for bitcoin and the I want to receive bitcoin and ethereum I tried this
pricesWs = new WebSocket(`wss://ws.coincap.io/prices?assets=bitcoin);
//then tried
pricesWs.send(bitcoin,ethereum)
this doesn't work, I also tried sending as JSON but I kept getting the same data just for the first query(bitcoin)
UPDATE:
This is the the Git for the app, if you are interested seeing the whole thing together.
Git
UPDATE 2:
I created this pen to make it easier to understand, note that the pen is made on VueJS, but that isn't important. The important part is on line 60 JS panel
Is there any reason why you want to switch the URL?
According to the coin cap documentation, you can request information about multiple crypto currency at once. Is it not an option for you?
Generally you should avoid opening and closing connections to a socket as there is slight latency albeit very insignificant. Leaving the connection open is better since you will be notified if price is changed for any of the currencies you are interested it.
The answer to your original question "Is it possible to change URL for a web socket connection?" is no! You can't change URL however you can create as many connections as you need. In your case you are closing the connection and opening it immediately but in the comments I noticed that you mentioned that it is based on user interaction. You can open connection just for the currencies you care about when user requests it and keep the connection opened until user switches the currency again because at that point you'll probably switch to another currency.
I also agree with #Taylor Spark, you can also just hide the dom for the currencies user don't care and render the ones they are interested in.
I am developing a chatbot using Dialogflow, I would like to throw a message to user when the chatbot doesn't understand the user input for three times in a row and for the forth time respond with a custom message (not the one of the options declared on the dialogflow interface)
One idea that I have is to make a counter within the input unknown action like this:
var counter = 1;
// The default fallback intent has been matched, try to recover (https://dialogflow.com/docs/intents#fallback_intents)
'input.unknown': () => {
// Use the Actions on Google lib to respond to Google requests; for other requests use JSON
if (requestSource === googleAssistantRequest) {
sendGoogleResponse('I\'m having trouble, can you try that again?'); // Send simple response to user
} else {
if (counter == 3) {
counter = 1;
sendResponse('Custom message');
} else {
counter++;
sendResponse('I\'m having trouble, can you try that again?'); // Send simple response to user
}
}
},
This would work, but idk if this will work for multiple user at the same time, I was thinking to create a storage for storing requests attached by a unique id and have a different counter for each request!
Do you have any better idea of achieving such thing in Dialogflow?
This will not work the way you've designed it. Not quite for the reason you think, but close.
You don't show the rest of your code (that's ok), but the counter variable is probably in a function that gets called each time it processes a message. When that function is finished, the counter variable goes out of scope - it is lost. Having multiple calls at the same time won't really be an issue since each call gets a different scope (I'm glossing over some technical details, but this should be good enough).
One solution is that you could store the variable in a global context - but then you do have the issue of multiple users ending up with the same counter. That is very very bad.
Your solution about keeping a counter in a database, keyed against the user, does make sense. But for this need, it is overkill. It is useful for saving data between conversations, but there are better ways to save information during the same conversation.
The easiest solution would be to use a Dialogflow Context. Contexts let you save state in between calls to your webhook fulfillment during the same conversation and for a specific number of messages received from the user (the lifespan).
In this case, it would be best if you created a context named something like unknown_counter with a lifespan of 1. In the parameters, you might set val to 1.
The lifespan of 1 would mean that you'll only see this context the next time your webhook is called. If they handle it through some other Intent (ie - you understood them), then the context would just vanish after your fulfillment runs.
But if your input.unknown handler is called again, then you would see the context was there and what the value is. If it doesn't meet the threshold, send the context again (with a lifespan of 1 again), but with the value being incremented by 1. If it did meet the threshold - you'd reply with some other answer and close the connection.
By "send the context", I mean that the context would be included as part of the reply. So instead of sending just a string to sendGoogleResponse() or sendResponse() you would send an object that included a speech property and an outputContexts property. Something like this:
var outputContexts = [
{
name: 'unknown_counter',
lifespan: 1,
parameters: {
'val': counterValue,
}
}
];
sendResponse({
speech: "I'm confused. What did you say?",
outputContexts: outputContexts
});
connection = new WebSocket("ws://localhost:1050/join?username=test")
connection.onopen = function(){
alert('Connection open!');
}
connection.onmessage = function(e){
var server_message = e.data;
alert(server_message);
}
connection.onclose = function() {
alert("websocket closing")
}
The connection to the server is established and an alert is displayed for Connection open! However immediately afterwards the connection closes. The server does not call close and there seem to be no other errors in the console. This is happening in both chrome and firefox.
I looked at a bunch of different similar examples on the web but to no avail.
to Keep Websocket Opened prevent handler from returning by return false; in connection.onmessage
like this :
connection.onmessage = function(e){
var server_message = e.data;
alert(server_message);
return false;
}
I believe I've stumbled across the solution that OP found but failed miserably to explain. I don't have enough reputation to comment, otherwise I'd be responding to all of the confused comments begging for clarification on OP's response.
The short version is that I think OP was referring to his server-side connection handler when he said "All I had to do was block the handler from returning before the websocket connection closes".
It turns out my server was closing the webSocket automatically because I didn't understand how a certain webSocket function worked. Specifically, I was using a Python server script with asyncio/websockets and the following code:
async def receiveCommandsLoop(player):
while True:
msg = await player.websocket.recv()
print(command)
async def handleClient(websocket, path):
username = await websocket.recv()
player = players[username]
...
#Start task to listen for commands from player
asyncio.get_event_loop().create_task(receiveCommandsLoop(player))
start_server = websockets.serve(handleClient, '', 8765)
The idea was that websockets.serve would use handleClient to begin the connection and do some setup, then create a new task with receiveCommandsLoop that would take over the job of communication.
But it turns out: when you call websockets.serve, Python expects that when your handler (in this case, handleClient) returns, you must be done with the socket, and it closes it automatically.
Thus, by the time receiveCommandsLoop was run, handleClient had returned, and the webSocket had been automatically closed.
I was able to fix this by simply modifying my handleClient function to directly run the loop originally contained in receiveCommandsLoop. Hope this helps someone out there.
This also could be the case when you're trying to send binary data over a websocket connection, but some side (client or server) is trying to interpret it as a text - many libraries and frameworks do it unless you explicitly specify you do want binary data.
It could also be a login problem. The websocket will automatically close the website required authentication but no authentication information was provided.
Piecing together hints from this post and others, I found a solution that works when using the python websocket server example found everywhere that includes something like:
async def handler(websocket, path):
data = await websocket.recv()
reply = f"Data recieved as: {data}!"
await websocket.send(reply)
To those of us new to websocket, I think the assumption is that the handler function will be called each time the client sends a message, which turns out not to be the case. As others mention, the connection closes as soon as the handler function returns once. The solution I found is to change it to:
async def handler(websocket, path):
async for data in websocket:
reply = f"Data recieved as: {data}!"
print(data)
await websocket.send(reply)
My client-side javascript code is equivalent to the OP's and I didn't have to change anything for this to work.
Unfortunately I can't explain why async for data in websocket: makes it actually wait forever and spontaneously run the inner code block each time a message is received, but it does for me and I get all the expected log messages both on the python server side and the client javascript console.
If anyone more knowledgeable on this topic can comment on whether this is a good-for-general-use solution or if there's a gotcha to look out for here, it would be much appreciated.
Fixed it!
All I had to do was block the handler from returning before the websocket connection closes
I am facing a strange issue with calling socket.on methods from the Javascript client. Consider below code:
for(var i=0;i<2;i++) {
var socket = io.connect('http://localhost:5000/');
socket.emit('getLoad');
socket.on('cpuUsage',function(data) {
document.write(data);
});
}
Here basically I am calling a cpuUsage event which is emitted by socket server, but for each iteration I am getting the same value. This is the output:
0.03549148310035006
0.03549148310035006
0.03549148310035006
0.03549148310035006
Edit: Server side code, basically I am using node-usage library to calculate CPU usage:
socket.on('getLoad', function (data) {
usage.lookup(pid, function(err, result) {
cpuUsage = result.cpu;
memUsage = result.memory;
console.log("Cpu Usage1: " + cpuUsage);
console.log("Cpu Usage2: " + memUsage);
/*socket.emit('cpuUsage',result.cpu);
socket.emit('memUsage',result.memory);*/
socket.emit('cpuUsage',cpuUsage);
socket.emit('memUsage',memUsage);
});
});
Where as in the server side, I am getting different values for each emit and socket.on. I am very much feeling strange why this is happening. I tried setting data = null after each socket.on call, but still it prints the same value. I don't know what phrase to search, so I posted. Can anyone please guide me?
Please note: I am basically Java developer and have a less experience in Javascript side.
You are making the assumption that when you use .emit(), a subsequent .on() will wait for a reply, but that's not how socket.io works.
Your code basically does this:
it emits two getLoad messages directly after each other (which is probably why the returning value is the same);
it installs two handlers for a returning cpuUsage message being sent by the server;
This also means that each time you run your loop, you're installing more and more handlers for the same message.
Now I'm not sure what exactly it is you want. If you want to periodically request the CPU load, use setInterval or setTimeout. If you want to send a message to the server and want to 'wait' for a response, you may want to use acknowledgement functions (not very well documented, but see this blog post).
But you should assume that for each type of message, you should only call socket.on('MESSAGETYPE', ) once during the runtime of your code.
EDIT: here's an example client-side setup for a periodic poll of the data:
var socket = io.connect(...);
socket.on('connect', function() {
// Handle the server response:
socket.on('cpuUsage', function(data) {
document.write(data);
});
// Start an interval to query the server for the load every 30 seconds:
setInterval(function() {
socket.emit('getLoad');
}, 30 * 1000); // milliseconds
});
Use this line instead:
var socket = io.connect('iptoserver', {'force new connection': true});
Replace iptoserver with the actual ip to the server of course, in this case localhost.
Edit.
That is, if you want to create multiple clients.
Else you have to place your initiation of the socket variable before the for loop.
I suspected the call returns average CPU usage at the time of startup, which seems to be the case here. Checking the node-usage documentation page (average-cpu-usage-vs-current-cpu-usage) I found:
By default CPU Percentage provided is an average from the starting
time of the process. It does not correctly reflect the current CPU
usage. (this is also a problem with linux ps utility)
But If you call usage.lookup() continuously for a given pid, you can
turn on keepHistory flag and you'll get the CPU usage since last time
you track the usage. This reflects the current CPU usage.
Also given the example how to use it.
var pid = process.pid;
var options = { keepHistory: true }
usage.lookup(pid, options, function(err, result) {
});