Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions web2/app/api/[...path]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,27 +106,20 @@ export async function GET(request: NextRequest, { params }: { params: { path: st
return NextResponse.json({ error: "Failed to fetch data" }, { status: 500 });
}
}

export async function POST(request: NextRequest, { params }: { params: { path: string[] } }) {

const url = new URL(request.url);
const path = url.pathname.replace("/api/", ""); // Remove "/api/" prefix

// if (!path) {
// return new Response("Invalid request", { status: 400 });
// }
//const path = params.path.join("/")
const path = url.pathname.replace("/api/", "");
const token = request.headers.get("Authorization")?.split(" ")[1];

const token = request.headers.get("Authorization")?.split(" ")[1]
let body = {}
let body = {};
try {
body = request.body ? await request.json() : {};
const text = await request.text();
body = text ? JSON.parse(text) : {};
} catch (error) {
console.error("Invalid JSON:", error);
return NextResponse.json({ error: "Invalid JSON input" }, { status: 400 });
}


try {
const response = await fetch(`${process.env.API_URL}/api/${path}`, {
method: "POST",
Expand All @@ -135,13 +128,20 @@ export async function POST(request: NextRequest, { params }: { params: { path: s
"Content-Type": "application/json",
},
body: JSON.stringify(body),
})
});

const data = await response.json()
return NextResponse.json(data, { status: response.status })
const responseText = await response.text();
console.log(responseText);

if (responseText.trim() !== "") {
const responseData = JSON.parse(responseText);
return NextResponse.json(responseData, { status: response.status });
} else {
return new Response(null, { status: response.status }); // <-- return something even if empty
}
} catch (error) {
console.error("API error:", error)
return NextResponse.json({ error: "Failed to post data" }, { status: 500 })
console.error("API error:", error);
return NextResponse.json({ error: "Failed to post data" }, { status: 500 });
}
}

Expand Down
137 changes: 121 additions & 16 deletions web2/app/api/sse/[...path]/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,55 @@
// // app/api/sse/[...path]/route.ts
// import { type NextRequest } from "next/server";

// export async function GET(request: NextRequest) {
// const url = new URL(request.url);
// const path = url.pathname.replace("/api/sse/", ""); // e.g., "timeline" or "comments/123"
// const token =
// url.searchParams.get("token") ||
// request.headers.get("Authorization")?.split(" ")[1];

// try {
// const backendResponse = await fetch(
// `${process.env.API_URL}/api/${path}?${url.searchParams.toString()}`,
// {
// method: "GET",
// headers: {
// Authorization: token ? `Bearer ${token}` : "",
// Accept: "text/event-stream",
// },
// }
// );

// // Proxy the backend SSE stream directly to the client
// console.log(backendResponse.body)
// // let passedValue = await new Response(backendResponse.body).text();
// // if (passedValue){
// // let valueToJson = JSON.parse(passedValue);
// // console.log("jsonval:", valueToJson)
// // }
// return new Response(backendResponse.body, {
// status: 200,
// headers: {
// "Content-Type": "text/event-stream",
// "Cache-Control": "no-cache",
// Connection: "keep-alive",
// // Optional headers for CORS (if needed):
// // "Access-Control-Allow-Origin": "*",
// },
// });
// } catch (error) {
// console.log("SSE proxy error:", error);
// return new Response("Failed to connect to SSE", { status: 502 });
// }
// }






// app/api/sse/[...path]/route.ts
import { type NextRequest } from "next/server";
import { type NextRequest, NextResponse } from "next/server";

export async function GET(request: NextRequest) {
const url = new URL(request.url);
Expand All @@ -8,37 +58,92 @@ export async function GET(request: NextRequest) {
url.searchParams.get("token") ||
request.headers.get("Authorization")?.split(" ")[1];

// --- Ensure token exists (optional but good practice) ---
if (!token) {
return new Response("Authentication token required", { status: 401 });
}
// --- ---

try {
const backendUrl = `${process.env.API_URL}/api/${path}`;
// Create a new URL object to safely append search params
const targetUrl = new URL(backendUrl);

// Forward existing search params EXCEPT the token we added client-side
url.searchParams.forEach((value, key) => {
if (key !== 'token') { // Don't forward the token query param if backend expects header
targetUrl.searchParams.append(key, value);
}
});


console.log(`Proxying SSE request to:${targetUrl.toString()}`);

const backendResponse = await fetch(
`${process.env.API_URL}/api/${path}?${url.searchParams.toString()}`,
targetUrl.toString(), // Use the constructed URL with search params
{
method: "GET",
headers: {
Authorization: token ? `Bearer ${token}` : "",
// Pass the token in the Authorization header to the actual backend
Authorization: `Bearer ${token}`,
Accept: "text/event-stream",
// Forward other relevant headers if needed
// 'X-Forwarded-For': request.ip ?? 'unknown',
},
// Important for streaming responses in Node fetch / Next.js Edge runtime
cache: 'no-store', // Ensure fresh data
// If using Node >= 18, duplex might be needed depending on the exact env
// duplex: 'half'
}
);

// Proxy the backend SSE stream directly to the client
console.log(backendResponse.body)
let passedValue = await new Response(backendResponse.body).text();
if (passedValue){
let valueToJson = JSON.parse(passedValue);
console.log("jsonval:", valueToJson)
// Check if the backend responded successfully
if (!backendResponse.ok) {
console.error(`SSE Backend error (${backendResponse.status}): ${await backendResponse.text()}`);
return new Response(`Backend request failed with status ${backendResponse.status}`, { status: backendResponse.status });
}

// Check if the backend response is actually an event stream
const contentType = backendResponse.headers.get("Content-Type");
if (!contentType || !contentType.includes("text/event-stream")) {
console.error(`Backend did not respond with Content-Type: text/event-stream. Received: ${contentType}`);
// Return an error, maybe log the response body if small
// const responseBody = await backendResponse.text();
// console.error("Backend response body:", responseBody);
return new Response("Backend did not return an event stream", { status: 502 }); // 502 Bad Gateway
}


// --- CORRECT WAY: Stream the backend response directly ---
// Ensure the body exists and is a ReadableStream
if (!backendResponse.body) {
console.error("Backend response body is null.");
return new Response("Backend response body is null", { status: 502 });
}
return new Response("", {
status: 200,

// Return the backend's stream directly to the client
console.log("body", backendResponse.body)
return new Response(backendResponse.body, {
status: 200, // Or backendResponse.status if you want to mirror it
headers: {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
Connection: "keep-alive",
// Optional headers for CORS (if needed):
// "Access-Control-Allow-Origin": "*",
"Connection": "keep-alive",
// Copy other relevant headers from backendResponse if needed
// e.g., backendResponse.headers.get('X-My-Custom-Header')
},
});
// --- ---

} catch (error) {
console.log("SSE proxy error:", error);
return new Response("Failed to connect to SSE", { status: 502 });
console.error("SSE proxy fetch error:", error);
// Check if it's a fetch error (e.g., connection refused)
if (error instanceof TypeError && error.message === 'fetch failed') {
return new Response("Failed to connect to the backend SSE service", { status: 502 }); // Bad Gateway might be appropriate
}
return new Response(`Internal Server Error: ${error instanceof Error ? error.message : 'Unknown error'}`, { status: 500 });
}
}

// Optional: Configure Edge Runtime for potentially better performance with streaming
// export const runtime = 'edge';
10 changes: 8 additions & 2 deletions web2/components/comments-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ export function CommentsList({ proseId }: { proseId: string }) {
})

useEffect(() => {
fetchComments()

if (data) {
setComments(data)
setIsLoading(false)
Expand All @@ -55,7 +57,7 @@ export function CommentsList({ proseId }: { proseId: string }) {
if (sseError) {
fetchComments()
}
}, [data, sseError])
}, [sseError])

const fetchComments = async () => {
try {
Expand All @@ -71,7 +73,10 @@ export function CommentsList({ proseId }: { proseId: string }) {

const data = await response.json()
console.log(data)
setComments(data)
if (data!=null){
setComments(data)
}
else setComments([])
} catch (err) {
toast({
title: "Error",
Expand All @@ -90,6 +95,7 @@ export function CommentsList({ proseId }: { proseId: string }) {
headers: {
Authorization: `Bearer ${token}`,
},
body: null
})

if (!response.ok) {
Expand Down
1 change: 1 addition & 0 deletions web2/components/timeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ export function Timeline() {
headers: {
Authorization: `Bearer ${token}`,
},
body: ""
});

if (!response.ok) {
Expand Down
16 changes: 9 additions & 7 deletions web2/lib/use-sse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -191,14 +191,16 @@ export function useSSE<T>(
eventSource.addEventListener(eventName, (event) => {
try {
console.log(`Received ${eventName} event:`, event);

if (event.data) {
console.log(event.data)

const parsedData = JSON.parse(event.data) as T;
setData(parsedData);
options.onMessage?.(parsedData);
if (event.data){
console.log("raw data", event.data)
}

// if (event.data) {
// console.log(event.data)
// const parsedData = JSON.parse(event.data) as T;
// setData(parsedData);
// options.onMessage?.(parsedData);
// }
} catch (err) {
console.error('Error parsing SSE data:', err);
const error = err instanceof Error ? err : new Error(String(err));
Expand Down
Loading