Botframework-webchat: Implement WebSocket message retrieval

Created on 16 Nov 2016  路  32Comments  路  Source: microsoft/BotFramework-WebChat

The version of the WebChat still using polling to get messages. How do I activate the WebSocket new feature?

All 32 comments

Direct Line 3.0 allows both GET and WebSocket to retrieve messages. We do plan to implement WebSocket support in WebChat in the future, but it's not available yet.

Great, thanks

Note that even once WebSocket is implemented, WebChat will still fallback to GET if the browser does not support WebSocket.

This is now working on a preview basis. You can pass webSocket: true when creating DirectLine. Or if you're using the provided samples/index.html, you can pass webSocket=true in the URL.

I will keep this issue open until we make WebSocket the default transport for receiving messages.

Hi,

For me websockets don't work. I keep getting the following error (visible only when debugging):

"Failed to construct 'WebSocket':
The URL 'v3/directline/conversations/9eRq1bOKuvU14n92KhViVH/stream?
watermark=-&t=GJdVApD6wRY.dA...DkAMgBLAGgAVgBpAFYAS
AA.qqdbi9ls0gE.MdTQRQVZwVk.38QPHxDs6DKLXPegWTTJq1CO9H615ITl2qvuxE_M7cs' is invalid."

I'm using the provided /samples/index.html page. You mentioend public/index.html but the only think I found there is a page showing a turtle...So, passing the webSocket=true parameter just fails. Any idea why?

Also, using the out of the box endpoint https://webchat.botframework.com/embed, webSocket has no effect although the enable preview checkbox is ticked in the webchat channel config. Are websockets usable with the online control or only via a custom built one?

Thanks

WebSocket is still in beta, and is not currently available in the preview version of the hosted WebChat channel, so yes you currently need to build your own control and enable WebSockets.

I updated the above comment to reflect the change from public -> samples, thanks.

I use WebChat with WebSockets most of the time, and they work fine for me so we'll have to dig into your details. What version of which browser are you using, how are you embedding the control? Are you just running samples/index.html directly, and if so can you provide the URL you're using (redacting your direct line secret of course).

Hi Bill,

thanks for your swift reply. I tried again and here is the full info:
URL I'm using:
http://169.254.46.96:8000/samples/index.html?s=GJdVApD__________-iRY_phHzffffhiuNtyTRSmjTZ2dA&webSocket=true

(I've obfuscated part of the secret here)

The code is going to the catch block of the following method:
private __tryOrSetError(parent: Subscriber, fn: Function, value?: any): boolean {
try {
fn.call(this._context, value);
} catch (err) {
parent.syncErrorValue = err;
parent.syncErrorThrown = true;
return true;
}
return false;
}
that is part of the Subscriber.ts script.

Returned error:

error code 12
message : "Failed to construct 'WebSocket': The URL 'v3/directline/conversations/7N8Dwv9jY7CErSVMEKXGiI/stream?watermark=-&t=GJdVApD6wRY.dAA.NwBOADgARAB3AHYAOQBqAFkANwBDAEUAcgBTAFYATQBFAEsAWABHAGkASQA.EWA0NPxs0gE.tnN4IL3pOJ8.zgg3uY5aWn5TW_kW4wkpwuW1BoARVQmjO7iuZ3yJ2f8' is invalid."
name : "SyntaxError"
stack : "Error: Failed to construct 'WebSocket': The URL 'v3/directline/conversations/7N8Dwv9jY7CErSVMEKXGiI/stream?watermark=-&t=GJdVApD6wRY.dAA.NwBOADgARAB3AHYAOQBqAFkANwBDAEUAcgBTAFYATQBFAEsAWABHAGkASQA.EWA0NPxs0gE.tnN4IL3pOJ8.zgg3uY5aWn5TW_kW4wkpwuW1BoARVQmjO7iuZ3yJ2f8' is invalid.
at Observable._subscribe (http://169.254.46.96:8000/webpacked/botchat.js:51264:23)
at Observable.subscribe (http://169.254.46.96:8000/webpacked/botchat.js:22235:28)
at RetryWhenOperator.call (http://169.254.46.96:8000/webpacked/botchat.js:35270:24)
at Observable.subscribe (http://169.254.46.96:8000/webpacked/botchat.js:22232:23)
at Object.subscribeToResult (http://169.254.46.96:8000/webpacked/botchat.js:24034:28)
at MergeMapSubscriber._innerSub (http://169.254.46.96:8000/webpacked/botchat.js:29958:39)
at MergeMapSubscriber._tryNext (http://169.254.46.96:8000/webpacked/botchat.js:29955:15)
at MergeMapSubscriber._next (http://169.254.46.96:8000/webpacked/botchat.js:29938:19)
at MergeMapSubscriber.Subscriber.next (http://169.254.46.96:8000/webpacked/botchat.js:22457:19)
at MergeMapSubscriber.notifyNext (http://169.254.46.96:8000/webpacked/botchat.js:29971:31)"

I tried with Chrome Version 55.0.2883.87 m but also with Firefox and Edge on two different machines and they all end up with the above error.

You now have the full info. Hope this helps and thanks again!

Edit : I realized that I forgot to mention how I call the page, I'm just running the URL directly in the browser, no embed.

Best Regards

That URL is very odd - it should look more like wss://directline.botframework.com/v3/directline/conversations/{conversationId}/stream?watermark=-&t={token}

Will you add a console.log("streamUrl", this.streamUrl); right after here and let me know what it says?

Here is what I get from Fiddler :
{
"conversationId": "HR2oZYGenM6EQKzX5Q4c7h",
"token": "GJdVApD6wRY.dAA.SABSADIAbwBaAFkARwBlAG4ATQA2AEUAUQBLAHoAWAA1AFEANABjADcAaAA.jge4ygZt0gE.vfFj4ifohWk.djNV-z2_t3kq8uQ0MctFPIB_Ng9BaJBCDKJ0hkUgnNA",
"expires_in": 1800,
"streamUrl": "v3/directline/conversations/HR2oZYGenM6EQKzX5Q4c7h/stream?watermark=-&t=GJdVApD6wRY.dAA.SABSADIAbwBaAFkARwBlAG4ATQA2AEUAUQBLAHoAWAA1AFEANABjADcAaAA.jhmZvQJt0gE.gRqIJyP5ztI.pqd8snmDug9myJzu0xqjxO0u5EeuK_UP2yLQ1cRlI-Q"
}
and here is what is logged in the console as you suggested:

v3/directline/conversations/HR2oZYGenM6EQKzX5Q4c7h/stream?watermark=-&t=GJdVApD6wRY.dAA.SABSADIAbwBaAFkARwBlAG4ATQA2AEUAUQBLAHoAWAA1AFEANABjADcAaAA.jhmZvQJt0gE.gRqIJyP5ztI.pqd8snmDug9myJzu0xqjxO0u5EeuK_UP2yLQ1cRlI-Q

The URL matches, I guess that you should concatenate wss:...+the url returned by directline?

Thanks

No, you should be getting the full URL. I'll pursue this and get back to you, thanks.

Of course, just doing this:

if(this.streamUrl.indexOf('wss')==-1)
{
this.streamUrl = 'wss://directline.botframework.com/'+this.streamUrl;
}
in directLine.ts does the trick but it's not very elegant. However, I have rebuilt and now websockets work fine.

@stephaneey you shouldn't need to do that but I'm glad you're unblocked for now.

Anyone else seeing this problem?

P.S. if (this.streamUrl.startsWith('wss')) ... - the magic of ES6!

Bill, another issue once you switch to webSocket is whenever I send a message, there is alternate HTTP post query (regular AJAX) that is systematically cancelled (see screenshot), causing the chat window to display "couldn't send...retry" for a while. With Edge and Firefox, the requests remain in "pending" as they use the "keep-alive" mechanism but every message creates a new connection. Display behavior is the same, it goes always in the "retry" mode.

It is a normal behavior to still send HTTP Post request intead of reusing the webSocket channel?

Chrome
errobot

Edge
boterror

Thanks

we only use WebSockets to receive messages, so this is yet a different strange behavior you are seeing that i've never seen or heard of before. Is your computer cursed?

ah ah :), same behavior again on two different machines and with 3 different browsers and with different wireless networks so I guess, this can't be my machine.
[edit:same on iPad], so it can't be a machine problem.

Bill, are you using the exact same version as the one that's currently available in this repo?

I sure am. So the one thing in common is that all these machines/browsers/networks are aiming at the same bot?

Will you set var botchatDebug=true in the console and see if you see any messages about web sockets being closed?

Here is the output when I send a message:

history action Object {type: "Send_Message", activity: Object}
botchat.js:21793 history action Object {type: "Send_Message_Try", clientActivityId: "1484323244757.3722033363586965.0"}
botchat.js:21793 postActivity Object {type: "message", text: "blabla", from: Object, locale: "fr", timestamp: "2017-01-13T16:00:59.202Z"鈥
botchat.js:21793 history action Object {type: "Show_Typing", activity: Object}
botchat.js:21793 history action Object {type: null}
botchat.js:21793 history action Object {type: "Receive_Message", activity: Object}
botchat.js:21793 history action Object {type: "Clear_Typing", id: "BbmRWIVGy2xKWuy4cd3EBX|9n6SgL8Iwm"}
botchat.js:21793 history action Object {type: null}
botchat.js:21793 history action Object {type: "Send_Message_Succeed", clientActivityId: "1484323244757.3722033363586965.0", id: "retry"}
botchat.js:21793 history action Object {type: null}
botchat.js:21793 history action Object {type: "Receive_Sent_Message", activity: Object}activity: Objecttype: "Receive_Sent_Message"__proto__: Object

and indeed, they all aim at the same bot, I will try with another one just to see

Ok I think I found the culprit : the timeout. I just amended my bot in order to simply answer "hello" whatever message is received and now, I don't have this problem anymore. If the bot takes more than 5 seconds (which is the case because it performs several sharepoint queries in a row after an interaction with LUIS). So, that's the reason. I noticed that the default timeout is 5000 milliseconds but I didn't really find where you defined that in the source code as things seems to be commented out. Note this seems specific to webSockets as I never faced this issue with the polling get mode..

I found a crappy way of increasing it but this made the trick:

for (var prop in urlOrRequest) {
if (urlOrRequest.hasOwnProperty(prop)) {
if (prop != 'timeout') {
request[prop] = urlOrRequest[prop];
}else
{
request[prop] = 10000;
}
}
}
and no more issue...if you could just indicate where the default timeout of 5000 is specified, that'd be great as I didn't manage to find it (made a search on 5000 in the entire folder...but no luck)

To be honest, 5000 is way too short if you work with LUIS dialogs. Simply resolving to the None intent and replying "I don't understand" is usually taking already about 5/6 seconds. This is increased by the 'typing' reply but even when removing it, it's really hard to get the right LUIS intent triggered below 5 secs.

thanks

That's great feedback, thanks. 5 secs was totally arbitrary. What do you personally think would be the right number? 10? 15? 20? The reason we have a limit at all is so that we can give up on a particular server instance that might be sick but not immediately failing, and hope we get a better one on the next try.

Here is where this is set in the code.

I think that at least 10 secs is necessary :)

I was low on coffee when I responded before.

The short timeout isn't a problem. Bots aren't synchronous. The DirectLine call to post an activity isn't waiting for your bot to respond, it's just posting your message into a queue and immediately returning. 5 seconds is a very reasonable amount of time for this to happen, but I might bump it up a bit.

Whether your bot takes a second to respond or ten minutes shouldn't be relevant at all. I just made a bot that takes 10 seconds to respond, and accessed it with WebSocket. Posting happened right away. The response took 10 seconds, as planned.

There is something weird going on with your bot, but I have no idea what it is.

Well, if I simply do this into my bot:

var cli = new ConnectorClient(new Uri(activity.ServiceUrl));
var rep = activity.CreateReply("test");
Thread.Sleep(16000); // now I've built the chat control with 15 secs
await cli.Conversations.ReplyToActivityAsync(rep);

after the switch block, there is also
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;

I reproduce the issue and the bot couldn't be simpler, so what am I missing here? So, whether they are synchronous or not, getting over the timeout results in that on all machines.

PS, here is the screenshot of the network call from Chrome, as you can see (highlighted in red) it stops right after the timeout:

botitmeout

Thanks
Best Regards

Bill, to add some more info, as you probably noticed yourself, this timeout issue isn't limited to webSocket, I get the exact same thing with polling get but there are many requests going on, that it is not as noticable as it is with websockets

pollingget

You see here, it fails after 5.01 seconds, the default timeout since I'm using the online webchat control against the same bot that I described above (sleeping 16 seconds). So, the HTTP post query waits until the bot responds and timeouts, even with the online webchat which we cannot configure.

Thanks
Best Regards

@stephaneey Okay I have an answer for your WebSocket problem. You registered your bot for the WebChat channel and are using the secret it gave you. But actually you need to register it for DirectLine and use that secret. This is causing the bug. In the future it won't even work at all to use a WebChat secret at DirectLine endpoints.

Will you please open up a separate issue for the other problem you're experiencing?

Hi Bill,

I confirm that I was indeed using the secret given by the webchat control. How is it going to work when you'll enable websockets with the online control because this is quite confusing.

Ok so this fixes the streamurl problem right but it doesn't explain the timeout thing, right?

Thanks

Right, that's why I asked you to file a separate issue. I agree that the naming is confusing. This is not a WebSockets issue, that was just a random bug. We will eventually enable WebSockets by default for the WebChat channel.

@stephaneey Ah I think I misunderstood your question. The reason this bug exists is that you were passing WebChat secrets to a DirectLine endpoint. Folks using WebChat secrets with the WebChat endpoint will have no problems, and soon the respective endpoints will only accept their own secrets.

@billba that's indeed what I meant. I created a separate issue https://github.com/Microsoft/BotFramework-WebChat/issues/288 for the network problem.

Best Regards

Now on by default (but currently off in the official WebChat channel)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

joshm998 picture joshm998  路  3Comments

electrobabe picture electrobabe  路  4Comments

felixhauserch picture felixhauserch  路  3Comments

filipjakov picture filipjakov  路  4Comments

AndreMantas picture AndreMantas  路  4Comments