ryanvolum / offline-directline

Unofficial package to emulate the bot framework connector locally.
https://www.npmjs.com/package/offline-directline
78 stars 44 forks source link

HTTP 400 on webchat connection to offline-directline #22

Open kriewall opened 6 years ago

kriewall commented 6 years ago

I'm getting an HTTP 400 Bad Request when I attempt to connect web chat to your offline-directline service, despite your clear usage documentation. I'm pretty certain that I'm missing something obvious; thought I'd inquire here in the hopes you can see what it is.

I've got a bot written in .NET fired up and listening on http://localhost:3979/api/Messages. I've got the following content in an app.js file and have it running via node app.js:

const directline = require("offline-directline");
const express = require("express");

const app = express();
directline.initializeRoutes(app, "http://127.0.0.1:3000", "http://127.0.0.1:3979/api/messages");

I've modified the FullWindow index.html as follows ... Chrome and Firefox were erroring out for favicon.ico retrieval, so I added the favicon.ico content to resolve that issue:

<!DOCTYPE html>
<html>
  <head>
    <link rel="icon" 
      type="image/ico"
      href="http://localhost:8000/favicon.ico">
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>Bot Chat</title>

    <link href="../../botchat.css" rel="stylesheet" />
    <link href="../../botchat-fullwindow.css" rel="stylesheet" />

    <style>
      html, body {
        height: 100%;
        margin: 0;
        overflow: hidden;
        padding: 0;
      }
    </style>
  </head>
  <body>
    <div id="BotChatGoesHere"></div>
    <script src="../../botchat.js"></script>
    <script>
      const params = BotChat.queryParams(location.search);

      const user = {
        id: params['userid'] || 'userid',
        name: params['username'] || 'username'
      };

      const bot = {
        id: params['botid'] || 'botid',
        name: params['botname'] || 'botname'
      };

      window['botchatDebug'] = params['debug'] && params['debug'] === 'true';

      BotChat.App({
        bot: bot,
        locale: params['locale'],
        resize: 'window',
        // sendTyping: true,    // defaults to false. set to true to send 'typing' activities to bot (and other users) when user is typing
        user: user,
        // locale: 'es-es', // override locale to Spanish

        directLine: {
          secret: params['s'],
          token: params['t'],
          domain: params['domain'],
          webSocket: false // defaults to true
        }
      }, document.getElementById('BotChatGoesHere'));
    </script>
  </body>
</html>

I'm opening web chat using Chrome at this URL: http://localhost:8000/samples/fullwindow/?domain=http://localhost:3000/directline&BotId=Test. I've tried it both with and without the BotId modifier. Either way, web chat starts up with no errors in npm, and the app.js service responds with `Created conversation with conversationId: {unique Guid}``. However, when I try to enter a message, it shows up in web chat with a little note "couldn't send".

Inspecting in Fiddler, there are two request-response pairs when the connection between web chat and offline-directline is made, the first of which succeeds with HTTP 200, the second fails with HTTP 400:

Pass (HTTP 200):
OPTIONS http://localhost:3000/directline/conversations HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://localhost:8000
User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36
Access-Control-Request-Headers: authorization,x-requested-with
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, PUT, POST, DELETE, PATCH, OPTIONS
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization
Allow: POST
Content-Type: text/html; charset=utf-8
Content-Length: 4
ETag: W/"4-Yf+Bwwqjx254r+pisuO9HfpJ6FQ"
Date: Wed, 16 May 2018 18:53:45 GMT
Connection: keep-aliveq

POST
Fail (HTTP 400):
POST http://localhost:3000/directline/conversations HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Content-Length: 0
Accept: application/json
Origin: http://localhost:8000
X-Requested-With: XMLHttpRequest
Authorization: Bearer undefined
User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36
Referer: http://localhost:8000/samples/fullwindow/?domain=http://localhost:3000/directline&BotId=Test
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
HTTP/1.1 400 Bad Request
X-Powered-By: Express
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, PUT, POST, DELETE, PATCH, OPTIONS
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization
Content-Type: application/json; charset=utf-8
Content-Length: 75
ETag: W/"4b-viC/2aaVSbzlx2kpl0w9rOF69h4"
Date: Wed, 16 May 2018 18:53:45 GMT
Connection: keep-alive

{"conversationId":"51938246-91a5-4d19-9a8c-f600ed06a70a","expires_in":1800}

I get the same HTTP 400 error using FireFox; IE11 is a non-starter since it returns an error `Object doesn't support property or method 'find'`` when I attempt to send a message. A breakpoint on the MessageController in my bot never gets hit, so there doesn't appear to be any dependence on the bot at this point. What am I doing wrong?

(P.S. Apologies if anything here is unclear. My background is in .NET desktop app development, so I'm trying to wrap my head around new technology content here.)

kriewall commented 6 years ago

I made some minor progress on this:

  1. The bot endpoint must be listed as "http://localhost:3979/api/messages". "http://127.0.0.1:3979/api/messages" does not work.
  2. The message activity must include IChannelAccount instances for from and recipient, otherwise the Conversation.SendAsync method will fail for a NullReferenceException.

These two changes get breakpoints firing in the bot and allow posting back to the user from the bot. This gets offline-directline to trigger messages such as 'Called POST setConversationData'. Unfortunately nothing seems to be sent back to web chat. From what I can understand of the code, it looks like there may be no mechanism to send bot responses back to the web chat. Perhaps I'm just overlooking something obvious - again, any guidance on the expected behavior or possible root causes would be appreciated.

ryanvolum commented 6 years ago

hey @kriewall, sorry for the late response. This is likely an issue with the way the endpoints that the .NET SDK calls vs the Node SDK (where I'm doing my testing). As you probably noticed in digging through the code, I haven't implemented every endpoint that the connector service does.

I'll try to do some digging on the .NET side and let you know what I find!

kriewall commented 6 years ago

Thanks @ryanvolum. I had a thought, but I'm not sure if it's plausible or not,.. I thought that perhaps the web chat client needs somehow to be configured to poll the GetActivities method on the Direct Line proxy, since the direct line connection has been reconfigured such that web sockets aren't used. This doesn't explain why you get round-trip communication with your setup, but it's the only hypothesis I've been able to come up with. Thoughts?

Your example has proven very helpful, btw - using your code as a reference, I've been able to get an equivalent implementation set up using .NET, with which I'm much more familiar. So thanks!

ryanvolum commented 5 years ago

Hey @kriewall - apologies for the radio silence on my end. I haven't been supporting this package, but it seems to have grown a following of its own. I'm glad to hear that you were able to get something working, even if it meant baking your own implementation. Is your connector open source? Would you be willing to share it with the community? I'd be happy to link to a nuget package if you had one.

I also wanted to reach out to see if the latest iteration of offline-directline works for your C# bot - some changes have been made to send properly formed conversationUpdate messages, which I suspect may have been the reason the C# SDK was rejecting messages.

Let me know!

kriewall commented 5 years ago

Hey @ryanvolum - my turn to apologize for the delay. My implementation isn't open source exactly, but from what I can tell, there's nothing proprietary in it. It is a very limited implementation, however, but hopefully enough to get one started - I basically set it up as a quick POC for a colleague. Since then I've moved off the project and into a different group, so I'm basically out of the picture at this point.

That said, I'd be happy to share what I put together, if I can find a spare moment. Time is at a premium right now, but when the opportunity presents I could fork your repo, add in my content as a subfolder, and submit a pull request. Would that work for you?

We never got around to checking the updated version of OLDL with our bot since we switched over to the C# version, so no new validations there. Sorry! :|

pradeepdeepu commented 5 years ago

Hi @kriewall,

I'm looking for the fix for the C# version. It would be really helpful for me. May i ask for the implementation you have put for consuming a C# sdk bot.?

Thank you.!!

biohazard999 commented 5 years ago

@ryanvolum I am facing the same issue, trying to include the recipient in the createConversationUpdateActivity function didn't do the trick. Still getting null in the C# bot when replying. Any ideas?

I made some minor progress on this:

  1. The bot endpoint must be listed as "http://localhost:3979/api/messages". "http://127.0.0.1:3979/api/messages" does not work.
  2. The message activity must include IChannelAccount instances for from and recipient, otherwise the Conversation.SendAsync method will fail for a NullReferenceException.

These two changes get breakpoints firing in the bot and allow posting back to the user from the bot. This gets offline-directline to trigger messages such as 'Called POST setConversationData'. Unfortunately nothing seems to be sent back to web chat. From what I can understand of the code, it looks like there may be no mechanism to send bot responses back to the web chat. Perhaps I'm just overlooking something obvious - again, any guidance on the expected behavior or possible root causes would be appreciated.