1

I'm implementing webchat with token based along with chat persistence everything works fine when user is online, but after some idle time if user is offline with no internet connectivity, for about 30-45 mins then later he gets back online and when ever he texting anything bot went to state DIRECT_LINE/POST_ACTIVITY_REJECTED and user was unable to chat with the bot its giving away send retry on my message bubble. Is there any way possible to handle?.

 (async function() {
    'use strict';
    const {
            hooks: { usePostActivity },
            hooks: { useDirection },
            ReactWebChat
    } = window.WebChat;
    
     let { token, conversation_Id } = sessionStorage;
    if ( !token ) {
                    const res = await fetch( 'https:/localhost/api/generateToken', { method: 'POST' } );
                    const { token: directLineToken, conversationId: conversationId } = await res.json();
                    sessionStorage[ 'token' ] = directLineToken;
                    sessionStorage[ 'conversation_Id' ] = conversationId;
                    token = directLineToken;
                    conversation_Id = conversationId;
                    }
                    
    if (token) {
        await setInterval(async () => {
        var myHeaders = new Headers();
        myHeaders.append("Authorization","Bearer "+ sessionStorage[ 'token' ]);
        let res = await fetch( 'https://directline.botframework.com/v3/directline/tokens/refresh', {
                                method: 'POST', 
                                headers: myHeaders,
                                });
        const { token: directLineToken, conversationId } = await res.json();
            sessionStorage[ 'token' ] = directLineToken;
            sessionStorage[ 'conversation_Id' ] = conversationId;
            token = directLineToken;
            conversation_Id = conversationId;
        }, 1000*60*15)}
        
                        
    
    
    const  store = window.WebChat.createStore({}, ({ dispatch }) => next => action => {
    if(action.payload && action.payload.directLine) {
        const subscription = action.payload.directLine.connectionStatus$.subscribe({
                error: error => console.log( error ),
                next: value => {
                        if ( value === 0 ) {console.log('Uninitialized')} 
                        else if ( value === 1 ) {console.log('Connecting')} 
                        else if ( value === 2 ) {console.log('Online')}
                        else if  ( value === 3 ) {console.log('Expire Token')}
                        else if ( value === 4 ) {console.log('FailedToConnect')}
                        else if ( value === 5 ) {console.log('Ended')}
                }
            });
        }
     if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
        dispatch({
                type: 'WEB_CHAT/SEND_EVENT',
                payload: {
                    name: 'Welcome',
                    value: { language: window.navigator.language }
                    }
                });
            }
            
    
    if (action.type === 'DIRECT_LINE/POST_ACTIVITY') {
                action = window.simpleUpdateIn(action, ['payload', 'activity', 'channelData', 'CustomChannel'], () =>"webchat");
                }
    
        return next(action);
    });
    
    
   const  botconnection = createDirectLine( {token,webSockets: true,watermark: "0" });
    
    window.ReactDOM.render(
    <ReactWebChat directLine={botconnection}
                  store={store}
        />,
        document.getElementById('webchat'));
        document.querySelector('#webchat > *').focus();
        })().catch(err => console.error(err));

note: token is not expired and If I refresh the page bot starts reponding.

KSK
  • 53
  • 6
  • Are you certain on the length of time elapsed? The tokens generated by Direct Line are valid for up to 60 mins before expiring and/or needing to be refreshed. If you are certain the elapsed time is correct, then I'd guess your method for maintaining persistence is flawed. In this case, could you update your post to include your Web Chat's code. Then I could study your implementation. – Steven Kanberg Nov 13 '20 at 02:29
  • Alternatively, you can look over [this SO answer](https://stackoverflow.com/a/56978924/3962636) that shows how I setup chat persistence. It is still susceptible to token expiry if I'm offline/navigated away longer than 60 mins, but it works flawlessly, otherwise. – Steven Kanberg Nov 13 '20 at 02:39
  • @StevenKanberg I had updated code here can please go through link https://stackoverflow.com/questions/64806603/refresh-directline-token-after-it-got-expired – KSK Nov 13 '20 at 04:46
  • Thanks @StevenKanberg but If I refresh the page bot starts responding properly...I have seen some chatbots having reconnect to bot, but not sure how to implement .. its only refreshing the page but I wanted only to refresh bot. – KSK Nov 13 '20 at 04:59
  • To be clear, when you refresh the page and the bot starts responding, is it continuing the conversation via persistence or starting a new one with a new token? – Steven Kanberg Nov 16 '20 at 23:59
  • @StevenKanberg with the old token only.. bot starts responding if it is less than an hour of token creation – KSK Nov 17 '20 at 12:18

1 Answers1

2

I made a few adjustments to the code you supplied. I believe your token value was getting overwritten or corrupted, so I separated out the assigning of the token in the API call (token) and the variable assignment in the script (dl_token).

I was also getting an error on the refresh token call wrapped in the setInterval() function, which is why I use Babel, as shown below. (For testing, it helps identify errors that would otherwise have been missed.). Removing the actual API call from setInterval() and calling it as a separate function seemed to fix this.

After these changes, everything seems to be working smoothly. I only tested a few times waiting until the 45-50 minute, but didn't experience any issues with the token, needing to refresh, or receiving DIRECT_LINE/POST_ACTIVITY_REJECTED.

(Note that I made calls to my own 'token' server for generating and refreshing the token.)

<script crossorigin="anonymous" src="https://unpkg.com/@babel/standalone@7.8.7/babel.min.js"></script>

<script type="text/babel" data-presets="es2015,react,stage-3">
  ( async function () {
    'use strict';
    const {
      ReactWebChat
    } = window.WebChat;

    let { dl_token, conversation_Id } = sessionStorage;
    
    if ( !dl_token ) {
      const res = await fetch( 'http://localhost:3500/directline/conversations', { method: 'POST' } );
      const { token, conversationId } = await res.json();
      sessionStorage[ 'dl_token' ] = token;
      sessionStorage[ 'conversation_Id' ] = conversationId;
      dl_token = token;
      conversation_Id = conversationId;
    }

    if ( dl_token === sessionStorage['dl_token'] ) {
      setInterval( () => {
        refreshToken()
      }, 1000 * 60 * 1 )
    }
    
    const refreshToken = async () => {
      const res = await fetch( 'http://localhost:3500/directline/refresh', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          token: dl_token
        })
      } );
      const { token, conversationId } = await res.json();
      sessionStorage[ 'dl_token' ] = token;
      sessionStorage[ 'conversation_Id' ] = conversationId;
      dl_token = token;
      conversation_Id = conversationId;
    }


    const store = window.WebChat.createStore( {}, ( { dispatch } ) => next => action => {
      if ( action.payload && action.payload.directLine ) {
        const subscription = action.payload.directLine.connectionStatus$.subscribe( {
          error: error => console.log( error ),
          next: value => {
            if ( value === 0 ) { console.log( 'Uninitialized' ) }
            else if ( value === 1 ) { console.log( 'Connecting' ) }
            else if ( value === 2 ) { console.log( 'Online' ) }
            else if ( value === 3 ) { console.log( 'Expire Token' ) }
            else if ( value === 4 ) { console.log( 'FailedToConnect' ) }
            else if ( value === 5 ) { console.log( 'Ended' ) }
          }
        } );
      }
      if ( action.type === 'DIRECT_LINE/CONNECT_FULFILLED' ) {
        dispatch( {
          type: 'WEB_CHAT/SEND_EVENT',
          payload: {
            name: 'Welcome',
            value: { language: window.navigator.language }
          }
        } );
      }


      if ( action.type === 'DIRECT_LINE/POST_ACTIVITY' ) {
        action = window.simpleUpdateIn( action, [ 'payload', 'activity', 'channelData', 'CustomChannel' ], () => "webchat" );
      }

      return next( action );
    } );


    const botconnection = await createDirectLine( { token: dl_token } );

    window.ReactDOM.render(
      <ReactWebChat directLine={botconnection}
        store={store}
      />,
      document.getElementById( 'webchat' ) );
    document.querySelector( '#webchat > *' ).focus();
  } )().catch( err => console.error( err ) );
</script>

Hope of help!

Steven Kanberg
  • 6,078
  • 2
  • 16
  • 35