Почему срабатывает одна из моих саг, а другая нет (настроена точно так же ... я думаю) - PullRequest
2 голосов
/ 17 июня 2020

Я новичок в redux-saga и уже пару дней искал решение моей проблемы, поэтому решил, что спрошу здесь, так как пришел пустой.

Я делаю правки в библиотеке microsoft botframework-webchat для проекта, над которым я работаю. Вместо использования прямой линии я пытаюсь сделать библиотеку botframework-webchat совместимой с signalR . В частности, я вношу изменения в пакеты core и component . Моя цель - имитировать c поток прямого сокращения строки, чтобы signalR работал в контексте библиотеки botframework-webchat.

Базовый c поток начинается с моего root проекта, простого веб-приложения React .

rootproject / WebChat. js

import ReactWebChat from 'botframework-webchat';
 render() {
    ...

    <ReactWebChat
      className={`${className || ''} web-chat`}
      signalR={this.signalRConnection}
      //directLine={this.createDirectLine(token)}
      store={store}
      styleSet={styleSet}
   />
 }

Для моих целей я отправляю либо соединение signalR, либо объект соединения directLine. Затем в рамках 'botframework-webchat' в пакете компонентов ReactWebChat проходит через серию передач и в конечном итоге оказывается здесь:

rootproject / botframework-webchat / botframework-webchat-component / Composer. js

useEffect(() => {
    if (signalR) {
      console.log("Dispatch signalR");
      dispatch(
        connectSignalRAction({
          signalR
        })
      );
    } 
    else {
      dispatch(
        createConnectAction({
          directLine,
          userID,
          username
        })
      );
    }

    return () => {
      dispatch(disconnect());
    };
  }, [dispatch, signalR, userID, username]);

И при отправке объекта прямого или сигнального соединения, это правильно отправляет соответствующее действие. Затем следует перехват этого действия. Это делается в базовом пакете botframework-webchat. Сначала я продемонстрирую этот поток, работающий через прямую линию.

rootproject / botframework-webchat / botframework-webchat-component / botframework-webchat-core / connect. js

const CONNECT = 'DIRECT_LINE/CONNECT';
const CONNECT_FULFILLED = `${CONNECT}_FULFILLED`;
const CONNECT_FULFILLING = `${CONNECT}_FULFILLING`;
const CONNECT_PENDING = `${CONNECT}_PENDING`;
const CONNECT_REJECTED = `${CONNECT}_REJECTED`;
const CONNECT_STILL_PENDING = `${CONNECT}_STILL_PENDING`;

export default function connect({ directLine, userID, username }) {
  return {
    type: CONNECT,
    payload: {
      directLine,
      userID,
      username
    }
  };
}

export { CONNECT, CONNECT_FULFILLED, CONNECT_FULFILLING, CONNECT_PENDING, CONNECT_REJECTED, CONNECT_STILL_PENDING };

Это срабатывает CONNECT и находится здесь:

rootproject / botframework-webchat / botframework-webchat-component / botframework-webchat- core / connectionStatusToNotificationSaga. js

/* eslint no-magic-numbers: ["error", { "ignore": [0, 1, 2, 3, 4] }] */

import { call, put, takeLatest } from 'redux-saga/effects';

import { CONNECT } from '../actions/connect';
import createPromiseQueue from '../createPromiseQueue';
import setNotification from '../actions/setNotification';

const CONNECTIVITY_STATUS_NOTIFICATION_ID = 'connectivitystatus';

function subscribeToPromiseQueue(observable) {
  const { push, shift } = createPromiseQueue();
  const subscription = observable.subscribe({ next: push });

  return {
    shift,
    unsubscribe() {
      subscription.unsubscribe();
    }
  };
}

function* connectionStatusToNotification({ payload: { directLine } }) {
  const { shift, unsubscribe } = subscribeToPromiseQueue(directLine.connectionStatus$);

  console.log("subscribe connection status: " + directLine.connectionStatus$);


  try {
    let reconnecting;

    for (;;) {
      const value = yield call(shift);

      switch (value) {
        case 0:
        case 1:
          yield put(
            setNotification({
              id: CONNECTIVITY_STATUS_NOTIFICATION_ID,
              level: 'info',
              message: reconnecting ? 'reconnecting' : 'connecting'
            })
          );

          break;

        case 2:
          reconnecting = 1;

          yield put(
            setNotification({
              id: CONNECTIVITY_STATUS_NOTIFICATION_ID,
              level: 'success',
              message: 'connected'
            })
          );

          break;

        case 3:
        case 4:
          reconnecting = 1;

          yield put(
            setNotification({
              id: CONNECTIVITY_STATUS_NOTIFICATION_ID,
              level: 'error',
              message: 'failedtoconnect'
            })
          );

          break;

        default:
          break;
      }
    }
  } finally {
    unsubscribe();
  }
}

export default function*() {
  yield takeLatest(CONNECT, connectionStatusToNotification);
}

Мне удалось установить точки останова в проекте и перейти к приведенному выше коду, поэтому он идет первым. Для справки, вот магазин и саги.

rootproject / botframework-webchat / botframework-webchat-component / botframework-webchat-core / createStore.ts

// This is for the racing between sagaMiddleware and store
/* eslint no-use-before-define: "off" */

import { applyMiddleware, createStore } from 'redux';
import createSagaMiddleware from 'redux-saga';

import reducer from './reducer';
import sagaError from './actions/sagaError';
import sagas from './sagas';

export default function createWebChatStore(initialState, ...middlewares):any {
  const sagaMiddleware = createSagaMiddleware({
    onError: (...args) => {
      const [err] = args;

      console.error(err);

      store.dispatch(sagaError());
    }
  });

  const store = createStore(
    reducer, 
    initialState || {},
    applyMiddleware(...middlewares, sagaMiddleware)
  );

  sagaMiddleware.run(sagas);

  return store;
}

rootproject / botframework-webchat / botframework-webchat-component / botframework-webchat-core / sagas. js

import { fork } from 'redux-saga/effects';

import clearSuggestedActionsOnPostActivitySaga from './sagas/clearSuggestedActionsOnPostActivitySaga';
import connectionStatusToNotificationSaga from './sagas/connectionStatusToNotificationSaga';
import connectionStatusUpdateSaga from './sagas/connectionStatusUpdateSaga';
import connectSaga from './sagas/connectSaga';
import connectSignalRSaga from './sagas/connectSignalRSaga';
import detectSlowConnectionSaga from './sagas/detectSlowConnectionSaga';
import emitTypingIndicatorToPostActivitySaga from './sagas/emitTypingIndicatorToPostActivitySaga';
import incomingActivitySaga from './sagas/incomingActivitySaga';
import markAllAsSpokenOnStopSpeakActivitySaga from './sagas/markAllAsSpokenOnStopSpeakActivitySaga';
import postActivitySaga from './sagas/postActivitySaga';
import sendEventToPostActivitySaga from './sagas/sendEventToPostActivitySaga';
import sendFilesToPostActivitySaga from './sagas/sendFilesToPostActivitySaga';
import sendMessageBackToPostActivitySaga from './sagas/sendMessageBackToPostActivitySaga';
import sendMessageToPostActivitySaga from './sagas/sendMessageToPostActivitySaga';
import sendPostBackToPostActivitySaga from './sagas/sendPostBackToPostActivitySaga';
import sendTypingIndicatorOnSetSendBoxSaga from './sagas/sendTypingIndicatorOnSetSendBoxSaga';
import speakActivityAndStartDictateOnIncomingActivityFromOthersSaga from './sagas/speakActivityAndStartDictateOnIncomingActivityFromOthersSaga';
import startDictateOnSpeakCompleteSaga from './sagas/startDictateOnSpeakCompleteSaga';
import startSpeakActivityOnPostActivitySaga from './sagas/startSpeakActivityOnPostActivitySaga';
import stopDictateOnCardActionSaga from './sagas/stopDictateOnCardActionSaga';
import stopSpeakingActivityOnInputSaga from './sagas/stopSpeakingActivityOnInputSaga';
import submitSendBoxSaga from './sagas/submitSendBoxSaga';
import submitSendBoxSagaSignalR from './sagas/submitSendBoxSagaSignalR';
import postActivitySagaSignalR from './sagas/postActivitySagaSignalR';
import sendMessageBackToPostActivitySagaSignalR from './sagas/sendMessageToPostActivitySagaSignalR';
import testSaga from './sagas/TestSaga';


export default function* sagas() {
  // TODO: [P2] Since fork() silently catches all exceptions, we need to find a way to console.error them out.

  yield fork(testSaga);
  yield fork(clearSuggestedActionsOnPostActivitySaga);
  yield fork(connectionStatusToNotificationSaga);
  yield fork(connectionStatusUpdateSaga);
  yield fork(connectSaga);
  yield fork(connectSignalRSaga);
  yield fork(detectSlowConnectionSaga);
  yield fork(emitTypingIndicatorToPostActivitySaga);
  yield fork(incomingActivitySaga);
  yield fork(markAllAsSpokenOnStopSpeakActivitySaga);
  yield fork(postActivitySaga);
  yield fork(sendEventToPostActivitySaga);
  yield fork(sendFilesToPostActivitySaga);
  yield fork(sendMessageBackToPostActivitySaga);
  yield fork(sendMessageToPostActivitySaga);
  yield fork(sendPostBackToPostActivitySaga);
  yield fork(sendTypingIndicatorOnSetSendBoxSaga);
  yield fork(speakActivityAndStartDictateOnIncomingActivityFromOthersSaga);
  yield fork(startDictateOnSpeakCompleteSaga);
  yield fork(startSpeakActivityOnPostActivitySaga);
  yield fork(stopDictateOnCardActionSaga);
  yield fork(stopSpeakingActivityOnInputSaga);
  yield fork(submitSendBoxSaga);
  yield fork(submitSendBoxSagaSignalR);
  yield fork(postActivitySagaSignalR);
  yield fork(sendMessageBackToPostActivitySagaSignalR);
}

Поток работает при использовании прямой линии, но затем, когда я отправляю через объект подключения signalR, который отправляет

      dispatch(
        connectSignalRAction({
          signalR
        })

, действие отправляется, но не принимается сагой. В частности, вот действие и сага:

rootproject / botframework-webchat / botframework-webchat-component / botframework-webchat-core / connectSignalR. js

const CONNECT_SIGNALR = 'SIGNALR/CONNECT';
const CONNECT_SIGNALR_FULFILLED = `${CONNECT_SIGNALR}_FULFILLED`;
const CONNECT_SIGNALR_FULFILLING = `${CONNECT_SIGNALR}_FULFILLING`;
const CONNECT_SIGNALR_PENDING = `${CONNECT_SIGNALR}_PENDING`;
const CONNECT_SIGNALR_REJECTED = `${CONNECT_SIGNALR}_REJECTED`;
const CONNECT_SIGNALR_STILL_PENDING = `${CONNECT_SIGNALR}_STILL_PENDING`;

export default function connectSignalR({ signalR }) {
  return {
    type: CONNECT_SIGNALR,
    payload: {
      signalR
    }
  };
}

export { CONNECT_SIGNALR, CONNECT_SIGNALR_FULFILLED, CONNECT_SIGNALR_FULFILLING, CONNECT_SIGNALR_PENDING, CONNECT_SIGNALR_REJECTED, CONNECT_SIGNALR_STILL_PENDING };

rootproject / botframework-webchat / botframework-webchat-component / botframework-webchat-core / connectSignalRSaga. js

/* eslint no-magic-numbers: ["error", { "ignore": [0, 10] }] */

import { call, cancel, cancelled, fork, put, race, take, takeEvery, takeLatest } from 'redux-saga/effects';

import { CONNECT_SIGNALR, CONNECT_SIGNALR_PENDING } from '../actions/connectSignalR';

function* workerSaga() {
  console.log("Hello from worker saga");
  yield put({ type: CONNECT_SIGNALR_PENDING });
}

export default function*() {
    // for (;;) {
    //   const {
    //     payload: { signalR }
    //   } = yield takeEvery(CONNECT_SIGNALR);

    // const {
    //   payload: { signalR }
    // } = yield takeEvery(CONNECT_SIGNALR, workerSaga);

    yield takeLatest(CONNECT_SIGNALR, workerSaga);

}

Я пробовал несколько разных подходов в 'connectSignalRSaga. js', но, похоже, не могу запустить workerSaga (), что заставляет меня думать, что функция по умолчанию никогда не срабатывает. Я пробовал использовать точки останова и оператор отладчика, и он не останавливается в этой функции (но точки останова и операторы отладчика по какой-то причине все равно по большей части не работают).

Итак, мои вопросы:

  1. Есть ли у вас какие-либо идеи, почему при использовании прямой линии выполняется действие «CONNECT», но когда с помощью signalr действие CONNECT_SIGNALR не выполняется?

  2. Слегка отстает от topi c, но у меня возникли проблемы с настройкой Redux DevTools для этого проекта (это isomorphi c Приложение React). Я выполнил инструкции из https://github.com/zalmoxisus/redux-devtools-extension#usage, но расширение продолжает говорить мне «Магазин не найден». Я пробовал обернуть магазин пакетом 'redux-devtools-extension' npm, а также настроить составление вручную. Я полагаю, что установка этой настройки поможет разобраться в №1.

1 Ответ

1 голос
/ 25 июня 2020

Веб-чат построен с использованием BotFramework-DirectLine JS, который является фактическим источником ConnectionStatus, отображаемого в веб-чате. Вы можете ссылаться на различные статусы здесь и то, как это перечисление используется в directLine.ts.

Более того, ConnectionStatus широко используется через веб-чат в connectSaga.js, connectionStatusUpdateSaga.js и множество других файлов.

Я сильно подозреваю, что ваше соединение SignalR на самом деле не выдает статус соединения, который в противном случае был бы обнаружен в веб-чате (если он был выдан, вообще). Кроме того, в соответствии с вашим соглашением об именовании состояний подключения SignalR, многие части веб-чата, вероятно, не улавливают его, если вы не обновили эти файлы для чтения из объекта подключения SignalR и распознавания обновленных статусов подключения.

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

...