Как поддерживать беседу в режиме онлайн-чата в течение более часа? - PullRequest
0 голосов
/ 06 февраля 2020

Я просмотрел документацию для botframework-webchat и не смог найти какой-либо документации о том, как правильно обрабатывать разговоры в течение 1 часа. Скорее всего, такая ситуация возникает, если веб-страница не используется в фоновом режиме в течение длительного периода времени.

Прямое соединение сохраняется до тех пор, пока веб-чат остается активным на веб-странице. Проблема возникает после обновления страницы sh.

Первоначальное краткосрочное решение заключается в хранении соответствующей информации разговора в хранилище сеанса, например токена. Проблема в том, что токен для разговора обновляется каждые 15 минут. Обновленный токен должен быть получен, чтобы поддерживать диалог при обновлении страницы sh.

Я уверен, что существует хакерский обходной путь для извлечения обновленного токена из объекта клиента прямой линии с использованием обратного вызова события.

В идеале я ищу чистый подход, разработанный для решения этой ситуации.

Хотя рабочее решение лучше, чем никакого решения.

Соответствующая ссылка: https://github.com/microsoft/BotFramework-WebChat

Спасибо.

Ответы [ 3 ]

0 голосов
/ 13 февраля 2020

Решение заключалось в сохранении идентификатора диалога в хранилище сеанса вместо токена. При обновлении страницы sh будет получен новый токен.

https://github.com/microsoft/BotFramework-WebChat/issues/2899

https://github.com/microsoft/BotFramework-WebChat/issues/2396#issuecomment -530931579

Это решение работает, но оно не оптимально. Лучшим решением было бы извлечь активный токен из объекта directline и сохранить его в хранилище сеансов. Проблема в том, что на данный момент не существует способа получения чистого способа получения обновленного токена из объекта прямой линии.

0 голосов
/ 13 февраля 2020

Этого можно добиться, внедрив куки на вашей стороне клиента. Вы можете установить срок действия файлов cookie равным 60 минутам, а также можете использовать водяной знак, чтобы сделать ваш чат постоянным в течение одного часа. Передача повара ie в службу бота и обратно .

0 голосов
/ 07 февраля 2020

Этого можно добиться, настроив сервер «токен». В приведенном ниже примере, я запускаю это локально, когда я разрабатываю / тестирую своего бота.

Вы можете использовать любой пакет, который хотите, однако я попал на «restify», потому что я включил его в файл index.js мой бот Я просто создаю новый сервер, отдельный от сервера бота, и назначаю ему собственный порт. Затем, когда я запускаю бот, он также запускается автоматически. Поместите свои appIds, appPasswords и секреты в файл .env.

Затем на своей веб-странице, на которой размещен ваш бот, просто вызовите конечную точку для получения токена. Вы также заметите, что код проверяет, существует ли токен. Если так, то он устанавливает интервал с таймером для обновления токена. Интервал в 1500000 мс устанавливается до того, как токен истечет (1800000 мс). Таким образом, токен всегда обновляется. (Только что всплыло у меня в голове: может быть разумно регистрировать оставшееся время и количество прошедшего времени, если пользователь ушел, чтобы установить интервал на точное число, чтобы он обновлялся, когда должен. В противном случае интервал будет сброшен со временем истечения, которое будет намного меньше.)

Кроме того, я включил закомментированный код. Это если вы хотите, чтобы ваши разговоры продолжались и после обновления страницы, или когда пользователь уходит и возвращается. Таким образом, текущие разговоры не теряются, а токен остается живым. Может не требоваться в зависимости от ваших потребностей, но хорошо работает с вышеперечисленным.

Надежда на помощь!


Сервер токенов

/**
 * Creates token server
 */
const path = require('path');
const restify = require('restify');
const request = require('request');
const bodyParser = require('body-parser');

const ENV_FILE = path.join(__dirname, '.env');
require('dotenv').config({ path: ENV_FILE });

const corsToken = corsMiddleware({
  origins: [ '*' ]
});

// Create HTTP server.
let server = restify.createServer();
server.pre(cors.preflight);
server.use(cors.actual);
server.use(bodyParser.json({
  extended: false
}));

server.listen(process.env.port || process.env.PORT || 3500, function() {
  console.log(`\n${ server.name } listening to ${ server.url }.`);
});

// Listen for incoming requests.
server.post('/directline/token', (req, res) => {
  // userId must start with `dl_`
  const userId = (req.body && req.body.id) ? req.body.id : `dl_${ Date.now() + Math.random().toString(36) }`;
  const options = {
    method: 'POST',
    uri: 'https://directline.botframework.com/v3/directline/tokens/generate',
    headers: {
      'Authorization': `Bearer ${ process.env.directLineSecret }`
    },
    json: {
      user: {
        ID: userId
      }
    }
  };
  request.post(options, (error, response, body) => {
    // response.statusCode = 400;
    if (!error && response.statusCode < 300) {
      res.send(body);
      console.log('Someone requested a token...');
    } else if (response.statusCode === 400) {
      res.send(400);
    } else {
      res.status(500);
      res.send('Call to retrieve token from DirectLine failed');
    }
  });
});

// Listen for incoming requests.
server.post('/directline/refresh', (req, res) => {
  // userId must start with `dl_`
  const userId = (req.body && req.body.id) ? req.body.id : `dl_${ Date.now() + Math.random().toString(36) }`;
  const options = {
    method: 'POST',
    uri: 'https://directline.botframework.com/v3/directline/tokens/refresh',
    headers: {
      'Authorization': `Bearer ${ req.body.token }`,
      'Content-Type': 'application/json'
    },
    json: {
      user: {
        ID: userId
      }
    }
  };
  request.post(options, (error, response, body) => {
    if (!error && response.statusCode < 300) {
      res.send(body);
      console.log('Someone refreshed a token...');
    } else {
      res.status(500);
      res.send('Call to retrieve token from DirectLine failed');
    }
  });
});

веб-чат. html

<script>
  (async function () {
    let { token, conversationId } = sessionStorage;

    [...]

    if ( !token || errorCode === "TokenExpired" ) {
      let res = await fetch( 'http://localhost:3500/directline/token', { method: 'POST' } );

      const { token: directLineToken, conversationId, error } = await res.json();
      // sessionStorage[ 'token' ] = directLineToken;
      // sessionStorage[ 'conversationId' ] = conversationId;
      token = directLineToken;
    }

    if (token) {
      await setInterval(async () => {
        let res = await fetch( 'http://localhost:3500/directline/refresh', {
          method: 'POST',
          headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
          },
          body: JSON.stringify( { token: token } )
        } );
        const { token: directLineToken, conversationId } = await res.json();
        // sessionStorage[ 'token' ] = directLineToken;
        // sessionStorage[ 'conversationId' ] = conversationId;
        token = directLineToken;
      }, 1500000)
    }

    // if ( conversationId ) {
    //   let res = await fetch( `https://webchat.botframework.com/v3/directline/conversations/${ conversationId }`, {
    //     method: 'GET',
    //     headers: {
    //       'Authorization': `Bearer ${ token }`,
    //       'Content-Type': 'application/json'
    //     },
    //   } );

    //   const { conversationId: conversation_Id, error } = await res.json();
    //   if(error) {
    //     console.log(error.code)
    //     errorCode = error.code;
    //   }
    //   conversationId = conversation_Id;
    // }

    [...]

    window.ReactDOM.render(
      <ReactWebChat
        directLine={ window.WebChat.createDirectLine({ token });
      />
    ),
    document.getElementById( 'webchat' );
  });
</script>
...