Reactjs twilio设备连接和重新连接

Reactjs twilio设备连接和重新连接,reactjs,twilio,Reactjs,Twilio,我正在尝试为twilio调用连接创建上下文api。如果我做得正确与否,我想从twilio专家那里得到帮助。在这种情况下,我试图做的是连接twilio设备,如果令牌过期,则重新连接。但是通过这种方式,呼出的电话还没有工作,我可以看到设备已经准备好打印在我的控制台上。当我尝试调用时,deviceInstance状态显示为空 我就是这样做的 import { Device, Connection } from 'twilio-client'; import twilioReducers from '

我正在尝试为twilio调用连接创建上下文api。如果我做得正确与否,我想从twilio专家那里得到帮助。在这种情况下,我试图做的是连接twilio设备,如果令牌过期,则重新连接。但是通过这种方式,呼出的电话还没有工作,我可以看到设备已经准备好打印在我的控制台上。当我尝试调用时,
deviceInstance
状态显示为空

我就是这样做的

import { Device, Connection } from 'twilio-client';

import twilioReducers from './twilioReducers';

interface ITwilioContext {
  // device?: Device;
  setDeviceOnline?: () => void;
  state: InitialStateType;
  dispatch: React.Dispatch<any>;
  handleDeviceOutgoing: (params: OutgoingProps) => void;
}

export const TwilioContext = createContext<ITwilioContext>({});

const TwilioProvider = ({ children }: { children: React.ReactNode }) => {
  const [deviceInstance, setDeviceInstance] = useState<Device | null>(null);
  const [activeWorkspaceId] = useLocalStorage('activeWorkspaceId', null);
  const { t } = useTranslation();

  const [getVoiceToken, { data }] = useLazyQuery(VOICE_TOKEN, {
    fetchPolicy: 'network-only',
    errorPolicy: 'ignore',
    onError: err => console.error(err),
  });

  // Commented inorder to prevent reintialization
  // const device = new Device();

  const initialState = { direction: '', showPhoneWidget: false };
  const [state, dispatch] = useReducer(twilioReducers, initialState);


  /* event handlers for twilio device */
  const handleDeviceReady = (device: Device) => {
    console.log('Device ready');
    setDeviceInstance(device);
  };

  const handleDeviceOffline = async (device: Device) => {
    console.log('Device offline', device);
    if (device.token) {
      const twilioTokenDecoded = jwtDecode<JwtPayload>(device.token);
      if ((twilioTokenDecoded as any).exp <= Date.now() / 1000) {
        await getVoiceToken({});
        console.log('twilio new token data', data);
      }
    }
  };

  const handleDeviceError = (error: Connection.Error) => {
    console.log('Device error', error);
    if (TWILIO_ERRORS[error.code] !== undefined) {
      ToastMessage({
        content: t(TWILIO_ERRORS[error.code].errorKey, TWILIO_ERRORS[error.code].message),
        type: 'danger',
      });
    }
  };
  /* ----------------------------- */

  /* handle incoming calls */
  const handleDeviceIncoming = (connection: Connection) => {
    console.log('incoming', connection);
    dispatch({
      type: ACTIONS.INCOMING_CALL,
      data: connection,
    });
    connection.on(deviceEvent.CANCEL, () => {
      console.log('incoming-cancel');
      dispatch({
        type: ACTIONS.INCOMING_CALL_CANCEL,
      });
    });

    connection.on(deviceEvent.DISCONNECT, () => {
      console.log('incoming-disconnect');
      dispatch({
        type: ACTIONS.INCOMING_CALL_DISCONNECT,
      });
    });

    connection.on(deviceEvent.ACCEPT, () => {
      console.log('incoming-call-accept');
      dispatch({
        type: ACTIONS.ANSWER_INCOMING_CALL,
      });
    });

    connection.on(deviceEvent.REJECT, () => {
      console.log('incoming-call-reject');
      dispatch({
        type: ACTIONS.REJECT_INCOMING_CALL,
        updateConversationStatus: true,
      });
    });
    connection.on(deviceEvent.ERROR, (err: Connection.Error) => {
      console.log('Connection error occured', err);
      dispatch({
        type: ACTIONS.INCOMING_CALL_ERROR,
        status: 'error',
      });
    });
  };
  /* ----------------------------- */

  /* handle outgoing calls */
  const handleDeviceOutgoing = (params: OutgoingProps) => {
    if (deviceInstance) {
      if (deviceInstance.isInitialized || deviceInstance.status() !== 'ready') {
        ToastMessage({ content: t('error.deviceSetup', 'Device is offline.'), type: 'danger' });
        return;
      }
      const connection = deviceInstance.connect(params); // copied from premvp
      dispatch({
        type: ACTIONS.OUTGOING_CALL_INITIATED,
        data: connection,
        status: 'connecting',
        channelId: params?.channel_sid,
      });
      connection.on(deviceEvent.RINGING, (val: boolean) => {
        if (val) {
          dispatch({
            type: ACTIONS.OUTGOING_CALL_RINGING,
          });
        }
      });

      connection.on(deviceEvent.CANCEL, () => {
        console.log('Connection cancelled');
        dispatch({
          type: ACTIONS.OUTGOING_CALL_DISCONNECT,
        });
      });

      connection.on(deviceEvent.DISCONNECT, (conn: Connection) => {
        // handle user hungup
        console.log('Connection disconnected', conn);
        dispatch({
          type: ACTIONS.OUTGOING_CALL_DISCONNECT,
        });
      });

      connection.on(deviceEvent.ACCEPT, (conn: Connection) => {
        console.log('Connected to the user', conn); // handle user answercall
        dispatch({
          type: ACTIONS.OUTGOING_CALL_ANSWERED,
        });
      });

      connection.on(deviceEvent.REJECT, (conn: Connection) => {
        console.log('Rejected', conn); // handle user answercall
        dispatch({
          type: ACTIONS.REJECT_OUTGOING_CALL,
        });
      });

      connection.on(deviceEvent.ERROR, (err: Connection.Error) => {
        console.log('Connection error occured', err);
      });
    } else {
      console.log('No Device Instance exist');
    }
  };
  /* ----------------------------- */

  useEffect(() => {
    const device = new Device();
    console.log('device', device, data);
    if (data?.getVoiceToken?.data?.voiceToken) {
      device.setup(data?.getVoiceToken?.data?.voiceToken, deviceConfig);
      device.on(deviceEvent.READY, handleDeviceReady);
      device.on(deviceEvent.OFFLINE, handleDeviceOffline);
      device.on(deviceEvent.ERROR, handleDeviceError);
      device.on(deviceEvent.INCOMING, handleDeviceIncoming);
    }
    return () => {
      device.destroy();
      setDeviceInstance(null);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [data?.getVoiceToken?.data?.voiceToken]);

  useEffect(() => {
    if (activeWorkspaceId !== '') {
      getVoiceToken({});
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [activeWorkspaceId]);

  const value = useMemo(() => {
    return {
      state,
      dispatch,
      deviceInstance,
      handleDeviceOutgoing,
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [state]);

  return <TwilioContext.Provider value={value}>{children}</TwilioContext.Provider>;
};

export default TwilioProvider;
从“twilio客户端”导入{Device,Connection};
从“/TwilioEducers”导入TwilioEducers;
接口ITwilioContext{
//设备?:设备;
setDeviceOnline?:()=>void;
状态:InitialStateType;
调度:反应,调度;
handleDeviceOutgoing:(参数:OutgoingProps)=>void;
}
export const TwilioContext=createContext({});
const TwilioProvider=({children}:{children:React.ReactNode})=>{
常量[deviceInstance,setDeviceInstance]=useState(null);
const[activeWorkspaceId]=useLocalStorage('activeWorkspaceId',null);
const{t}=useTranslation();
const[getVoiceToken,{data}]=useLazyQuery(VOICE_TOKEN{
fetchPolicy:“仅限网络”,
errorPolicy:“忽略”,
onError:err=>console.error(err),
});
//注释以防止重新激活
//const device=新设备();
const initialState={direction:'',showPhoneWidget:false};
const[state,dispatch]=useReducer(twilioReducers,initialState);
/*twilio设备的事件处理程序*/
const handledevicerady=(设备:设备)=>{
console.log(“设备就绪”);
设置设备状态(设备);
};
const handleDeviceOffline=异步(设备:设备)=>{
console.log(“设备脱机”,设备);
if(设备令牌){
const TwilioTokendecode=jwtDecode(device.token);
如果((如有)。exp{
console.log('设备错误',错误);
if(TWILIO_错误[error.code]!==未定义){
演讲信息({
内容:t(TWILIO_错误[error.code].errorKey,TWILIO_错误[error.code].message),
类型:“危险”,
});
}
};
/* ----------------------------- */
/*接听来电*/
const handleDeviceIncoming=(连接:连接)=>{
console.log('传入',连接);
派遣({
类型:ACTIONS.INCOMING_CALL,
数据:连接,
});
connection.on(deviceEvent.CANCEL,()=>{
console.log('incoming-cancel');
派遣({
类型:ACTIONS.INCOMING\u CALL\u CANCEL,
});
});
connection.on(deviceEvent.DISCONNECT,()=>{
console.log('incoming-disconnect');
派遣({
类型:ACTIONS.INCOMING\u CALL\u DISCONNECT,
});
});
connection.on(deviceEvent.ACCEPT,()=>{
console.log('incoming-call-accept');
派遣({
类型:ACTIONS.ANSWER\u传入\u呼叫,
});
});
connection.on(deviceEvent.REJECT,()=>{
console.log(“传入呼叫-拒绝”);
派遣({
类型:ACTIONS.REJECT_传入_呼叫,
updateConversationStatus:true,
});
});
connection.on(deviceEvent.ERROR,(err:connection.ERROR)=>{
console.log('发生连接错误',err);
派遣({
类型:ACTIONS.INCOMING\u CALL\u ERROR,
状态:“错误”,
});
});
};
/* ----------------------------- */
/*处理外线电话*/
const handledeviceoutgo=(参数:OutgoingProps)=>{
if(设备持续时间){
if(deviceInstance.isInitialized | | deviceInstance.status()!='ready'){
ToastMessage({content:t('error.deviceSetup','Device is offline',键入'danger'});
返回;
}
const connection=deviceInstance.connect(params);//从premvp复制
派遣({
类型:ACTIONS.Outing_CALL_INITIATED,
数据:连接,
状态:“正在连接”,
channelId:params?.channel_sid,
});
connection.on(deviceEvent.RINGING)(val:boolean)=>{
if(val){
派遣({
类型:ACTIONS.outing\u CALL\u RINGING,
});
}
});
connection.on(deviceEvent.CANCEL,()=>{
console.log(“连接已取消”);
派遣({
类型:ACTIONS.outing\u CALL\u DISCONNECT,
});
});
connection.on(deviceEvent.DISCONNECT)(连接:连接)=>{
//处理用户hungup
console.log(“连接断开”,连接);
派遣({
类型:ACTIONS.outing\u CALL\u DISCONNECT,
});
});
connection.on(deviceEvent.ACCEPT,(conn:connection)=>{
console.log('Connected to the user',conn);//处理用户应答呼叫
派遣({
类型:ACTIONS.outing\u CALL\u responsed,
});
});
connection.on(deviceEvent.REJECT)(连接:连接)=>{
console.log('Rejected',conn);//处理用户应答呼叫
派遣({
类型:ACTIONS.REJECT_传出_呼叫,
});
});
connection.on(deviceEvent.ERROR,(err:connection.ERROR)=>{
console.log('发生连接错误',err);
});
}否则{
log('不存在设备实例');
}
};
/* ----------------------------- */
useffect(()=>{
const device=新设备();
console.log('设备'、设备、数据);
if(数据?.getVoiceToken?.data?.voiceToken){
设备设置(数据?.getVoiceToken?.data?.voiceToken,设备配置);
设备打开(deviceEvent.READY,handleDeviceReady);
device.on(deviceEvent.OFFLINE,handleDeviceOffline);
device.on(deviceEvent.ERROR,handleDeviceError);
设备上(deviceEvent.INCOMING,handleDeviceIncoming);
}
return()=>{
destroy();
setDeviceInstance(空);
};
//eslint禁用下一行react HOOK/deps
},[data?.getVoiceToken?.data?.voiceToken]);
useffect(()=>{
如果(activeWorkspaceId!=''){
getVoiceToken({});
}
//eslint禁用下一行反应挂钩/排气