Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Offline Mode Chat Issues: Message Sending Errors and Unnecessary API Calls #2737

Closed
Vijay-Magadum opened this issue Oct 29, 2024 · 14 comments
Closed

Comments

@Vijay-Magadum
Copy link

Vijay-Magadum commented Oct 29, 2024

hey Guys,
I have enabled offline support by adding the enableOfflineSupport prop to the chat component, and I am able to retrieve channels while offline. I have also added a database logger to track the queries for each operation. However, my problem arises when using the chat in offline mode. It is not sending messages and is throwing errors. Additionally, the event API is triggered for every word I type, which should be ignored while in offline mode. How can I fix these issues? Please help me with this.

Simulator.Screen.Recording.-.iPhone.16.Pro.-.2024-10-29.at.10.46.59.mp4
@ruturaj-hegana
Copy link

Could you please provide more details on how you are handling the client?

@Vijay-Magadum
Copy link
Author

I have stacked my chat component around stack screens as below:

<PaperProvider>
      <UserNetworkProvider>
        <UserAuthProvider>
          <GetStreamChatComponent theme={theme}>
            <ApiDataProvider>
              <SelectedDataProvider>
                <SelectedChannelProvider>
                  <StackScreens />
                </SelectedChannelProvider>
              </SelectedDataProvider>
            </ApiDataProvider>
          </GetStreamChatComponent>
        </UserAuthProvider>
      </UserNetworkProvider>
    </PaperProvider>

then i am handling client. connect method in my GetStreamChatComponent as below:


QuickSqliteClient.logger = (level, message, extraData) => {
  console.log(
    level,
    `QuickSqliteClient-------------- from logger: ${message}`,
    extraData
  );
};
const GetStreamChatComponent: React.FC<GetStreamChatComponentProps> = ({
  children,
  theme,
  ...props
}) => {
  const chatClient = StreamMethods.getChatClient();
  const [streamLanguage, setStreamLanguage] = useState<any>(null);
  const { t } = useTranslation();
  const [isClientReady, setIsClientReady] = useState(false);
  const { loading, user, isLoggedIn } = useAuthContext();

  // useEffect(() => {
  //   const getLanguage = async () => {
  //     const language = await initializeLanguage();
  //     setStreamLanguage(language);
  //   };
  //   getLanguage();
  // }, [isLoggedIn]);
  useEffect(() => {
    const startChat = async () => {
      try {
        const userData = {
          id: user.id,
        };
        console.log("userData- - - -- - - -", userData);
        const token = await StreamMethods.getStoredStreamToken();
        console.log("Token- - - -- - - -", token);
        if (!isClientReady) {
          const connectPromise = chatClient.connectUser(userData, token);
          console.log("connectPromise- - - -- - - -", connectPromise);
          setIsClientReady(true); // this allows components to render

          // await connectPromise;
        }

        console.log(
          "---------------- User connected to Stream Chat ------------",
          chatClient?.userId
        );
      } catch (e) {
        console.log("error while connecting user from stream component", e);
      }
    };
    console.log(
      "isLoggedIn- - - -- ---------******************* *************** - -",
      isLoggedIn
    );
    if (isLoggedIn) startChat();
  }, [isLoggedIn]);

  if (!isClientReady && isLoggedIn) return null;
  return (
    <GestureHandlerRootView style={{ flex: 1 }}>
      <OverlayProvider i18nInstance={streamLanguage}>
        <Chat
          client={chatClient}
          style={theme}
          // i18nInstance={streamLanguage}
          enableOfflineSupport
          ImageComponent={FastImage}
        >
          {children}
        </Chat>
      </OverlayProvider>
    </GestureHandlerRootView>
  );
};

const styles = StyleSheet.create({
  flex: {
    flex: 1,
  },
  errorText: {
    textAlign: "center",
    color: "red",
    margin: 10,
  },
});

export default GetStreamChatComponent;

and also i have declared chat client into my seperate stream class like below:

private _client: StreamChat<DefaultStreamChatGenerics> = this.initChatClient();
private initChatClient() {
    const client = StreamChat.getInstance(APIKey, {
      allowServerSideConnect : false,
      enableInsights: true,
      persistUserOnConnectionFailure: true,
      warmUp: true,
    });
    client.axiosInstance.interceptors.request.use(AxiosLogger.requestLogger);
    client.axiosInstance.interceptors.response.use(AxiosLogger.responseLogger);
    return client;
  }

@isekovanic
Copy link
Contributor

Hi @Vijay-Magadum ,

Sending messages failing while in offline mode is definitely expected and is the intended behaviour. Since you're offline the messages automatically get marked as errored ones and once you've regained connection you can retry sending those.

Not particularly sure why the errors occur with the typing API but I'll have a look at that and get back to you.

@Vijay-Magadum
Copy link
Author

hey @isekovanic is there any API method that can track all unsend messages and once i go online it will automatically send all those messages to that specific channels?

@isekovanic
Copy link
Contributor

Hi @Vijay-Magadum , there is nothing out of the box for this behaviour and I unfortunately cannot give you an estimate on if/when this would be added to our upstream.

You can try playing around with channel.messageSets or the channel.latestMessages() and look at the status of those messages to try to figure out whether it's failed or not and then react to this accordingly, but these are mostly internal APIs and we cannot guarantee everything in your specific integration would work immediately.

@Vijay-Magadum
Copy link
Author

Thanks @isekovanic, I will check this out in the meantime

@isekovanic
Copy link
Contributor

Hi @Vijay-Magadum, I opened a PR that should fix the the typing event warnings you've been getting while offline. You should get notified on this GH issue whenever it's merged and deployed and we can close it then. Thanks for the report !

@Vijay-Magadum
Copy link
Author

Sure @isekovanic, also in the terminal i am getting errors as below and for sending message i am getting axios timout error and when i turn on internet the message will not deliver, i have to press on resend button manually everytime, so is it expected or needs to be checked?

WARN  failed to do start typing event, ran into error:  [AxiosError: timeout of 3000ms exceeded]
WARN  failed to do stop typing event, ran into error:  [AxiosError: timeout of 3000ms exceeded]
LOG  [AxiosError: timeout of 3000ms exceeded].

@isekovanic
Copy link
Contributor

Yes, that's expected as mentioned above - we do not automatically send failed messages, but rather give the user the responsibility to do so at their own leisure.

@isekovanic
Copy link
Contributor

Hi @Vijay-Magadum ,

Release v5.41.2 is out: https://github.com/GetStream/stream-chat-react-native/releases/tag/v5.41.2.

Can you please try on this one and see if the issues persist (regarding the warnings).

@Vijay-Magadum
Copy link
Author

Vijay-Magadum commented Nov 5, 2024

hey @isekovanic, Yeah the issue is gone but it is occurring some time until i reload the app in offline mode

@Vijay-Magadum
Copy link
Author

Yes, that's expected as mentioned above - we do not automatically send failed messages, but rather give the user the responsibility to do so at their own leisure.

should we expect this change in v6 or are you thinking of changing this in later releases? If not then can we change some methods from module and make it work for us that can show one tic in offline mode

@isekovanic
Copy link
Contributor

hey @isekovanic, Yeah the issue is gone but it is occurring some time until i reload the app in offline mode

This might be the leeway time required for our SDK to figure out its websocket connection has died (i.e internet has gone down). This doesn't happen every time the net connection flickers but rather has a buffer. Also, if you're testing on a simulator for this and in a debug build, keep in mind that connects/disconnects to Metro might be causing this entire process to slow down a bit (since we're actually interested whether the WS connection has failed rather than if the internet flickered in order to send these events, since if it recovers we'd like to resend them for sure).

Yes, that's expected as mentioned above - we do not automatically send failed messages, but rather give the user the responsibility to do so at their own leisure.

should we expect this change in v6 or are you thinking of changing this in later releases? If not then can we change some methods from module and make it work for us that can show one tic in offline mode

We might have this in our roadmap but it's really early to say right now since we have other priorities. For now, you can perhaps try looking at this hook. It is an internal one and not really meant to be used externally, but it's a simpler one so it might be okay for you. It should contain the latest messages and within their bodies you can see them as failed by their status.

Unfortunately there isn't anything else available that I could offer right now.

@Vijay-Magadum
Copy link
Author

hey @isekovanic, Thanks for the fix and the clarification

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants