Description
I am trying o implement react-native-sse in my react native application. I have converted the code from the web application which is already implemented using @microsoft/fetch-event-source. In there it is working without any issues.
But when I try to do the same implementation in react native app using react-native-sse it is always going to error. I wonder if I have missed anything or implemented anything wrong in the react-native code. I am passing all the values and necessary things as passed in the web application (values message and attachments are not empty and passing the value from props). I am new to sse and this is my first time implementing.
This is my coding for reference =>
`import 'react-native-get-random-values';
import {v4} from 'uuid';
import EventSource, {EventSourceListener} from 'react-native-sse';
import {BaseURL} from '../../utils/serviceURL';
import {getUserToken} from '../../asyncStorage/dataStore';
import {DeviceEventEmitter} from 'react-native';
const ABORT_STREAM_EVENT = 'abortStreamEvent'; // Define the abort event constant
export async function baseHeaders(): Promise<{Authorization: string | null}> {
const basicAuth = await getUserToken();
return {
Authorization: basicAuth ? 'Bearer ${basicAuth}' : null,
};
}
export const multiplexStream = async function ({
workspaceSlug,
threadSlug = null,
prompt,
chatHandler,
attachments = [],
}: {
workspaceSlug: string;
threadSlug?: string | null;
prompt: string;
chatHandler: (chat: any) => void;
attachments?: any[];
}) {
if (threadSlug) {
return streamChat({slug: threadSlug}, prompt, chatHandler, attachments);
}
return streamChat({slug: workspaceSlug}, prompt, chatHandler, attachments);
};
export const streamChat = async function (
{slug}: {slug: string},
message: string,
handleChat: (chat: any) => void,
attachments: any[] = [],
) {
const ctrl = new AbortController();
// Listen for the ABORT_STREAM_EVENT key to be emitted by the client
const subscription = DeviceEventEmitter.addListener(
ABORT_STREAM_EVENT,
() => {
ctrl.abort();
handleChat({id: v4(), type: 'stopGeneration'});
},
);
// Create the EventSource instance
const eventSource = new EventSource(
`${BaseURL}workspace/${slug}/stream-chat`,
{
method: 'POST',
headers: await baseHeaders(),
body: JSON.stringify({message, attachments}),
},
);
const listener: EventSourceListener = (event: any) => {
if (event.type === 'open') {
console.log('Open SSE connection.');
if (event.ok) {
return; // everything's good
} else if (
event.xhrStatus >= 400 &&
event.xhrStatus < 500 &&
event.xhrStatus !== 429
) {
handleChat({
id: v4(),
type: 'abort',
textResponse: null,
sources: [],
close: true,
error: `An error occurred while streaming response. Code ${
event.xhrStatus
}. Message - ${JSON.parse(event.message).error}`,
});
ctrl.abort();
throw new Error('Invalid Status code response.');
} else {
handleChat({
id: v4(),
type: 'abort',
textResponse: null,
sources: [],
close: true,
error: `An error occurred while streaming response. Unknown Error.`,
});
ctrl.abort();
throw new Error('Unknown error');
}
} else if (event.type === 'message') {
try {
const chatResult = JSON.parse(event.data);
handleChat(chatResult);
} catch (error) {
console.error('Failed to parse message:', error);
}
} else if (event.type === 'error') {
const data = JSON.parse(event.message);
handleChat({
id: data.id || v4(),
type: data.type || 'abort',
textResponse: data.textResponse || null,
sources: data.source || [],
close: data.close || true,
error: `An error occurred while streaming response. Code ${
event.xhrStatus
}. Message - ${JSON.parse(event.message).error}`,
});
ctrl.abort();
} else if (event.type === 'exception') {
console.error('Error:', JSON.parse(event.message).error, event.xhrStatus);
}
};
eventSource.addEventListener('open', listener);
eventSource.addEventListener('message', listener);
eventSource.addEventListener('error', listener);
return () => {
eventSource.close();
subscription.remove();
};
};`
If anyone can help me identify if I have done something wrong or may be I may need to make any changes in the server side?
In the react application, this is how it is implemented =>
`multiplexStream: async function ({
workspaceSlug,
threadSlug = null,
prompt,
chatHandler,
attachments = [],
}) {
if (!!threadSlug)
return this.threads.streamChat(
{ workspaceSlug, threadSlug },
prompt,
chatHandler,
attachments
);
return this.streamChat(
{ slug: workspaceSlug },
prompt,
chatHandler,
attachments
);
},
streamChat: async function ({ slug }, message, handleChat, attachments = []) {
const ctrl = new AbortController();
// Listen for the ABORT_STREAM_EVENT key to be emitted by the client
// to early abort the streaming response. On abort we send a special `stopGeneration`
// event to be handled which resets the UI for us to be able to send another message.
// The backend response abort handling is done in each LLM's handleStreamResponse.
window.addEventListener(ABORT_STREAM_EVENT, () => {
ctrl.abort();
handleChat({ id: v4(), type: "stopGeneration" });
});
await fetchEventSource(`${API_BASE}/workspace/${slug}/stream-chat`, {
method: "POST",
body: JSON.stringify({ message, attachments }),
headers: baseHeaders(),
signal: ctrl.signal,
openWhenHidden: true,
async onopen(response) {
if (response.ok) {
return; // everything's good
} else if (
response.status >= 400 &&
response.status < 500 &&
response.status !== 429
) {
handleChat({
id: v4(),
type: "abort",
textResponse: null,
sources: [],
close: true,
error: `An error occurred while streaming response. Code ${response.status}`,
});
ctrl.abort();
throw new Error("Invalid Status code response.");
} else {
handleChat({
id: v4(),
type: "abort",
textResponse: null,
sources: [],
close: true,
error: `An error occurred while streaming response. Unknown Error.`,
});
ctrl.abort();
throw new Error("Unknown error");
}
},
async onmessage(msg) {
try {
const chatResult = JSON.parse(msg.data);
handleChat(chatResult);
} catch {}
},
onerror(err) {
handleChat({
id: v4(),
type: "abort",
textResponse: null,
sources: [],
close: true,
error: `An error occurred while streaming response. ${err.message}`,
});
ctrl.abort();
throw new Error();
},
});
},`
Any help would be really helpful as I am trying this for more than a week to identify what the issue is. As the react application is working, backend developer are not supporting to debug or change the code.