mirror of
https://github.com/fosrl/pangolin.git
synced 2025-08-21 01:38:34 +02:00
87 lines
2.6 KiB
TypeScript
87 lines
2.6 KiB
TypeScript
|
import axios from "axios";
|
||
|
import logger from "@server/logger";
|
||
|
import { ExitNode } from "@server/db";
|
||
|
|
||
|
interface ExitNodeRequest {
|
||
|
remoteType: string;
|
||
|
localPath: string;
|
||
|
method?: "POST" | "DELETE" | "GET" | "PUT";
|
||
|
data?: any;
|
||
|
queryParams?: Record<string, string>;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sends a request to an exit node, handling both remote and local exit nodes
|
||
|
* @param exitNode The exit node to send the request to
|
||
|
* @param request The request configuration
|
||
|
* @returns Promise<any> Response data for local nodes, undefined for remote nodes
|
||
|
*/
|
||
|
export async function sendToExitNode(
|
||
|
exitNode: ExitNode,
|
||
|
request: ExitNodeRequest
|
||
|
): Promise<any> {
|
||
|
if (!exitNode.reachableAt) {
|
||
|
throw new Error(
|
||
|
`Exit node with ID ${exitNode.exitNodeId} is not reachable`
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// Handle local exit node with HTTP API
|
||
|
const method = request.method || "POST";
|
||
|
let url = `${exitNode.reachableAt}${request.localPath}`;
|
||
|
|
||
|
// Add query parameters if provided
|
||
|
if (request.queryParams) {
|
||
|
const params = new URLSearchParams(request.queryParams);
|
||
|
url += `?${params.toString()}`;
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
let response;
|
||
|
|
||
|
switch (method) {
|
||
|
case "POST":
|
||
|
response = await axios.post(url, request.data, {
|
||
|
headers: {
|
||
|
"Content-Type": "application/json"
|
||
|
}
|
||
|
});
|
||
|
break;
|
||
|
case "DELETE":
|
||
|
response = await axios.delete(url);
|
||
|
break;
|
||
|
case "GET":
|
||
|
response = await axios.get(url);
|
||
|
break;
|
||
|
case "PUT":
|
||
|
response = await axios.put(url, request.data, {
|
||
|
headers: {
|
||
|
"Content-Type": "application/json"
|
||
|
}
|
||
|
});
|
||
|
break;
|
||
|
default:
|
||
|
throw new Error(`Unsupported HTTP method: ${method}`);
|
||
|
}
|
||
|
|
||
|
logger.info(`Exit node request successful:`, {
|
||
|
method,
|
||
|
url,
|
||
|
status: response.data.status
|
||
|
});
|
||
|
|
||
|
return response.data;
|
||
|
} catch (error) {
|
||
|
if (axios.isAxiosError(error)) {
|
||
|
logger.error(
|
||
|
`Error making ${method} request (can Pangolin see Gerbil HTTP API?) for exit node at ${exitNode.reachableAt} (status: ${error.response?.status}): ${error.message}`
|
||
|
);
|
||
|
} else {
|
||
|
logger.error(
|
||
|
`Error making ${method} request for exit node at ${exitNode.reachableAt}: ${error}`
|
||
|
);
|
||
|
}
|
||
|
throw error;
|
||
|
}
|
||
|
}
|