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

Event-Source onMessage is not triggering for both android and iOS platform. #70

Open
amit13091992 opened this issue Nov 19, 2024 · 14 comments

Comments

@amit13091992
Copy link

amit13091992 commented Nov 19, 2024

I have a project in react native CLI.

  "react": "^18.2.0",
  "react-native": "^0.73.9",
  "react-native-sse": "^1.2.1"

Usage:

   const createVitalsEventSource = async () => {
       const url = `EVENT_SOURCE_WEB_SOCKET_URL`;

       const eventSource = new EventSource(url, {
           headers: {
               Authorization: `Bearer ${token}`,
           },
           withCredentials: true,
           lineEndingCharacter: '\n',
           debug: true,
           pollingInterval: 0,
           timeoutBeforeConnection: 1000,
       });
       eventSourceRef.current = eventSource;

       const listener: EventSourceListener = (event: any) => {
           if (event.type === "open") {
               console.log('openSSEConnection');
           } else if (event.type === "message") {
               console.log('getting event message');
           } else if (event.type === "error") {
               console.log('getting event error');
           } else if (event.type === "close") {
               console.log('closing event source');
           }
       };
       eventSource.addEventListener("open", listener);
       eventSource.addEventListener("message", listener);
       eventSource.addEventListener("error", listener);
       eventSource.addEventListener("close", listener);
   };

It was working around a week back but suddenly stopped working.
Note: In Android, it is not at all working so I needed to use another library "react-native-oksse"

@amit13091992 amit13091992 changed the title Event-Source onMessage is not working for both android and iOS platform. Event-Source onMessage is not triggering for both android and iOS platform. Nov 19, 2024
@EmilJunker
Copy link
Contributor

To get SSE working on Android with React Native versions prior to 0.74, you have to disable the Flipper plugin. See https://stackoverflow.com/questions/69235694/react-native-cant-connect-to-sse-in-android/69235695#answer-69235695

As long as Flipper is enabled, SSE won't work in debug builds on Android.

If you run into more issues, please share the logs with us so we can see what is going on.

@amit13091992
Copy link
Author

To get SSE working on Android with React Native versions prior to 0.74, you have to disable the Flipper plugin. See https://stackoverflow.com/questions/69235694/react-native-cant-connect-to-sse-in-android/69235695#answer-69235695

As long as Flipper is enabled, SSE won't work in debug builds on Android.

If you run into more issues, please share the logs with us so we can see what is going on.

Okay but should work in iOS thought right ?

@EmilJunker
Copy link
Contributor

Okay but should work in iOS thought right ?

Yes, but we can only help you if you show us the logs.

@amit13091992
Copy link
Author

@EmilJunker
Please find below logs that I receive when I start connecting using Event source:

 DEBUG  [EventSource] Will open new connection in 1000 ms.
 DEBUG  [EventSource][onreadystatechange] ReadyState: HEADERS_RECEIVED(2), status: 200
 DEBUG  [EventSource][onreadystatechange] ReadyState: LOADING(3), status: 200
 LOG  Open SSE connection.
 DEBUG  [EventSource][onreadystatechange][OPEN] Connection opened.
 DEBUG  [EventSource][onreadystatechange] ReadyState: LOADING(3), status: 200
 DEBUG  [EventSource][onreadystatechange] ReadyState: LOADING(3), status: 200
 DEBUG  [EventSource][onreadystatechange] ReadyState: LOADING(3), status: 200

After waiting for 5 to 10 minutes, it remains the same. I have already attached a code reference. If any other additional information is needed please let me know.

@EmilJunker
Copy link
Contributor

If everything was working correctly, there should be a lot more log messages of the kind

 DEBUG  [EventSource][onreadystatechange] ReadyState: LOADING(3), status: 200

Are you sure that the SSE endpoint you connect to is working properly? I find it suspicious that a week ago everything was working fine and it suddenly stopped. This sounds like a backend issue to me.

@amit13091992
Copy link
Author

amit13091992 commented Nov 20, 2024

t to is working properly? I find it suspicious that a week ago everything was working fine and it suddenly stopped. This sounds like a backend issue to me.

I have checked from backend side, after confirming i.e. nothing changed from backend, I checked on the app side.

@EmilJunker Could you please help me out on this issue, as suddenly It stopped working, it has become a blocker :(

@EmilJunker
Copy link
Contributor

Does your app work if you connect to this SSE test endpoint instead of the actual backend?
https://fetch-eventstream.glitch.me/sse

@amit13091992
Copy link
Author

amit13091992 commented Nov 20, 2024

Does your app work if you connect to this SSE test endpoint instead of the actual backend? https://fetch-eventstream.glitch.me/sse

    const testingEventSource = async () => {
    const url = `https://fetch-eventstream.glitch.me/sse`;
    const eventSource = new EventSource(url, {
    });
    eventSourceRef.current = eventSource;

    const listener: EventSourceListener = (event: any) => {
        console.log(t('calling event source ' + JSON.stringify(event)));
        if (event.type === "open") {
            console.log('openSSEConnection');
        } else if (event.type === "message") {
        } else if (event.type === "error") {
            console.error('connectionError', event.message);
        } else if (event.type === "close") {
            console.error("Error: ", event.message, event.error);
        }
    };

    eventSource.addEventListener("open", listener);
    eventSource.addEventListener("message", listener);
    eventSource.addEventListener("error", listener);
    eventSource.addEventListener("close", listener);
};

LOGS:
LOG calling event source {"type":"open"}
LOG Open SSE connection.

After this, nothing comes in logs. @EmilJunker

@EmilJunker
Copy link
Contributor

Sorry, I forgot to tell you to add an event listener for the "increment" event like so:

eventSource.addEventListener("increment", (event) => {
  console.log(event.data);
});

@amit13091992
Copy link
Author

amit13091992 commented Nov 20, 2024

const testingEventSource = async () => {
        const url = `https://fetch-eventstream.glitch.me/sse`;

        const eventSource = new EventSource(url, {
        });
        eventSourceRef.current = eventSource;

        const listener: EventSourceListener = (event: any) => {
            console.log(t('calling event source ' + JSON.stringify(event)));
            if (event.type === "open") {
                console.log('openSSEConnection');
            } else if (event.type === "message") {
                console.log('openSSEConnection message: ' + JSON.stringify(event.data));
            } else if (event.type === "increment") {
                console.log('openSSEConnection increment: ' + JSON.stringify(event.data));
            } else if (event.type === "error") {
                console.error('connectionError', event.message);
            } else if (event.type === "close") {
                console.error("Error: ", event.message, event.error);
            }
        };
        eventSource.addEventListener("open", listener);
        eventSource.addEventListener("message", listener);
        eventSource.addEventListener("increment", listener);
        eventSource.addEventListener("error", listener);
        eventSource.addEventListener("close", listener);
    };

Updated Library code like below:

```
    export type BuiltInEventType = 'open' | 'message' | 'error' | 'close' | 'increment';
    export type EventType<E extends string = never> = E | BuiltInEventType;
    
    export interface MessageEvent {
      type: 'message';
      data: string | null;
      lastEventId: string | null;
      url: string;
    }

    export interface IncrementEvent {
      type: 'increment';
      data: string | null;
      lastEventId: string | null;
      url: string;
    }
    
    export interface OpenEvent {
      type: 'open';
    }
    
    export interface CloseEvent {
      type: 'close';
    }
    
    export interface TimeoutEvent {
      type: 'timeout';
    }
    
    export interface ErrorEvent {
      type: 'error';
      message: string;
      xhrState: number;
      xhrStatus: number;
    }
    
    export interface CustomEvent<E extends string> {
      type: E;
      data: string | null;
      lastEventId: string | null;
      url: string;
    }
    
    export interface ExceptionEvent {
      type: 'exception';
      message: string;
      error: Error;
    }
    
    export interface EventSourceOptions {
      method?: string;
      timeout?: number;
      timeoutBeforeConnection?: number;
      withCredentials?: boolean;
      headers?: Record<string, any>;
      body?: any;
      debug?: boolean;
      pollingInterval?: number;
      lineEndingCharacter?: string;
    }
    
    type BuiltInEventMap = {
      'message': MessageEvent,
      'open': OpenEvent,
      'increment': IncrementEvent,
      'close': CloseEvent,
      'error': ErrorEvent | TimeoutEvent | ExceptionEvent,
    };
    
    export type EventSourceEvent<E extends T, T extends string = any> = E extends BuiltInEventType ? BuiltInEventMap[E] : CustomEvent<E>;
    export type EventSourceListener<E extends string = never, T extends EventType<E> = EventType<E>> = (
      event: EventSourceEvent<T>
    ) => void;
    
    declare class EventSource<E extends string = never> {
      constructor(url: URL | string, options?: EventSourceOptions);
      open(): void;
      close(): void;
      addEventListener<T extends EventType<E>>(type: T, listener: EventSourceListener<E, T>): void;
      removeEventListener<T extends EventType<E>>(type: T, listener: EventSourceListener<E, T>): void;
      removeAllEventListeners<T extends EventType<E>>(type?: T): void;
      dispatch<T extends EventType<E>>(type: T, data: EventSourceEvent<T>): void;
    }
    
    export default EventSource;

 LOG  calling event source {"type":"open"}
 LOG  openSSEConnection
 LOG  calling event source {"type":"increment","data":"hello from SSE #0","url":"https://fetch-eventstream.glitch.me/sse","lastEventId":"0"}
 LOG  openSSEConnection increment: "hello from SSE #0"
 LOG  calling event source {"type":"increment","data":"hello from SSE #1","url":"https://fetch-eventstream.glitch.me/sse","lastEventId":"1"}
 LOG  openSSEConnection increment: "hello from SSE #1"
 LOG  calling event source {"type":"increment","data":"hello from SSE #2","url":"https://fetch-eventstream.glitch.me/sse","lastEventId":"2"}
 LOG  openSSEConnection increment: "hello from SSE #2"
 LOG  calling event source {"type":"increment","data":"hello from SSE #3","url":"https://fetch-eventstream.glitch.me/sse","lastEventId":"3"}
 LOG  openSSEConnection increment: "hello from SSE #3"
 LOG  calling event source {"type":"increment","data":"hello from SSE #4","url":"https://fetch-eventstream.glitch.me/sse","lastEventId":"4"}

@EmilJunker
Copy link
Contributor

Good, so the example from glitch.me works.

I don't know yet why it's not working with your other backend, though. I think it might be related to the lineEndingCharacter option that you specify. Have you tried it without that option?

By the way, you don't need to edit the library code to add custom events (like "increment"). You can do that with a type parameter like so:

type CustomEvents = 'increment' | 'decrement';

const eventSource = new EventSource<CustomEvents>(url, {});

const listener: EventSourceListener<CustomEvents> = (event) => {
    ...
};

eventSource.addEventListener('increment', listener);

@amit13091992
Copy link
Author

@EmilJunker with my implementation, I am attaching token as well in the header i.e. the change which I have in my implementation. I have added latest change you suggested for the increment one. But still the issue persists.
Logic:

 const callEventSourceAPI = async () => {
     const url = `MY_URL`;

     const eventSource = new EventSource(url, {
         headers: {
             Authorization: `Bearer ${token}`,
         },
         withCredentials: true,
         lineEndingCharacter: '\n',
         debug: true,
         pollingInterval: 0,
         timeoutBeforeConnection: 1000,
     });
     eventSourceRef.current = eventSource;

     const listener: EventSourceListener = (event: any) => {
         console.log(t('calling event source ' + JSON.stringify(event)));
         if (event.type === "open") {
             console.log('openSSEConnection');
         } else if (event.type === "message") {
             console.log('openSSEConnection message: ' + JSON.stringify(event.data));
         } else if (event.type === "increment") {
             console.log('openSSEConnection increment: ' + JSON.stringify(event.data));
         } else if (event.type === "error") {
             console.error('connectionError', event.message);
         } else if (event.type === "close") {
             console.error("Error: ", event.message, event.error);
         }
     };
     eventSource.addEventListener("open", listener);
     eventSource.addEventListener("message", listener);
     eventSource.addEventListener("increment", listener);
     eventSource.addEventListener("error", listener);
     eventSource.addEventListener("close", listener);
 };

LOGS:

       DEBUG  [EventSource] Will open new connection in 1000 ms.
       DEBUG  [EventSource] Will open new connection in 1000 ms.
       DEBUG  [EventSource][onreadystatechange] ReadyState: HEADERS_RECEIVED(2), status: 200
       DEBUG  [EventSource][onreadystatechange] ReadyState: LOADING(3), status: 200
       LOG  calling event source {"type":"open"}
       LOG  openSSEConnection
       DEBUG  [EventSource][onreadystatechange][OPEN] Connection opened.
       DEBUG  [EventSource][onreadystatechange] ReadyState: LOADING(3), status: 200
       DEBUG  [EventSource][onreadystatechange] ReadyState: LOADING(3), status: 200
       DEBUG  [EventSource][onreadystatechange] ReadyState: LOADING(3), status: 200
       DEBUG  [EventSource][onreadystatechange] ReadyState: LOADING(3), status: 200

@amit13091992
Copy link
Author

I think it might be related to the lineEndingCharacter option that you specify. Have you tried it without that option?

tried this but didn't help. @EmilJunker

@EmilJunker
Copy link
Contributor

@amit13091992 Sorry, I'm out of ideas. I don't see anything wrong with your code. I still think it must be a backend issue. I'm afraid you're on your own - good luck!

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

No branches or pull requests

2 participants