2024-01-31 23:57:57 +08:00
|
|
|
|
/* eslint-disable @typescript-eslint/naming-convention */
|
|
|
|
|
import * as http from "http";
|
|
|
|
|
import * as querystring from "querystring";
|
|
|
|
|
import { logger } from "../util/logger";
|
|
|
|
|
|
|
|
|
|
import { getServicePort } from "./endpoints/getServicePort";
|
|
|
|
|
import { installPythonEnv } from "./endpoints/installPythonEnv";
|
|
|
|
|
import { logError, logInfo, logWarn } from "./endpoints/ideLogging";
|
|
|
|
|
import { updateSlashCommands } from "./endpoints/updateSlashCommands";
|
|
|
|
|
import { ideLanguage } from "./endpoints/ideLanguage";
|
|
|
|
|
import { LegacyEndpoints } from "./endpoints/legacy";
|
|
|
|
|
import { UnofficialEndpoints } from "./endpoints/unofficial";
|
2024-02-01 12:01:01 +08:00
|
|
|
|
import { getDocumentSymbols } from "./endpoints/getDocumentSymbols";
|
2023-11-29 23:34:15 +08:00
|
|
|
|
|
|
|
|
|
const functionRegistry: any = {
|
2024-01-31 23:57:57 +08:00
|
|
|
|
/**
|
|
|
|
|
* Official IDE Service Protocol Endpoints
|
|
|
|
|
*/
|
|
|
|
|
"/get_lsp_brige_port": {
|
|
|
|
|
keys: [],
|
|
|
|
|
handler: getServicePort,
|
|
|
|
|
},
|
|
|
|
|
"/install_python_env": {
|
|
|
|
|
keys: ["command_name", "requirements_file"],
|
|
|
|
|
handler: installPythonEnv,
|
|
|
|
|
},
|
|
|
|
|
"/update_slash_commands": {
|
|
|
|
|
keys: [],
|
|
|
|
|
handler: updateSlashCommands,
|
|
|
|
|
},
|
|
|
|
|
"/ide_language": {
|
|
|
|
|
keys: [],
|
|
|
|
|
handler: ideLanguage,
|
|
|
|
|
},
|
|
|
|
|
"/log_info": {
|
|
|
|
|
keys: ["message"],
|
|
|
|
|
handler: logInfo,
|
|
|
|
|
},
|
|
|
|
|
"/log_warn": {
|
|
|
|
|
keys: ["message"],
|
|
|
|
|
handler: logWarn,
|
|
|
|
|
},
|
|
|
|
|
"/log_error": {
|
|
|
|
|
keys: ["message"],
|
|
|
|
|
handler: logError,
|
|
|
|
|
},
|
2024-02-01 12:01:01 +08:00
|
|
|
|
"/get_document_symbols": {
|
|
|
|
|
keys: ["abspath"],
|
|
|
|
|
handler: getDocumentSymbols,
|
|
|
|
|
},
|
2024-01-31 23:57:57 +08:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @deprecated
|
|
|
|
|
*/
|
|
|
|
|
"/definitions": {
|
|
|
|
|
keys: ["abspath", "line", "character", "token"],
|
|
|
|
|
handler: LegacyEndpoints.definitions,
|
|
|
|
|
},
|
|
|
|
|
/**
|
|
|
|
|
* @deprecated
|
|
|
|
|
*/
|
|
|
|
|
"/references": {
|
|
|
|
|
keys: ["abspath", "line", "character"],
|
|
|
|
|
handler: LegacyEndpoints.references,
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Unofficial endpoints
|
|
|
|
|
*/
|
|
|
|
|
"/visible_lines": {
|
|
|
|
|
keys: [],
|
|
|
|
|
handler: UnofficialEndpoints.visibleLines,
|
|
|
|
|
},
|
|
|
|
|
"/selected_lines": {
|
|
|
|
|
keys: [],
|
|
|
|
|
handler: UnofficialEndpoints.selectedLines,
|
|
|
|
|
},
|
|
|
|
|
"/diff_apply": {
|
|
|
|
|
keys: ["filepath", "content"],
|
|
|
|
|
handler: UnofficialEndpoints.diffApply,
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
"/document_symbols": {
|
|
|
|
|
keys: ["abspath"],
|
|
|
|
|
handler: UnofficialEndpoints.documentSymbols,
|
|
|
|
|
},
|
|
|
|
|
"/workspace_symbols": {
|
|
|
|
|
keys: ["query"],
|
|
|
|
|
handler: UnofficialEndpoints.workspaceSymbols,
|
|
|
|
|
},
|
|
|
|
|
"/find_definition": {
|
|
|
|
|
keys: ["abspath", "line", "col"],
|
|
|
|
|
handler: UnofficialEndpoints.findDefinition,
|
|
|
|
|
},
|
|
|
|
|
"/find_type_definition": {
|
|
|
|
|
keys: ["abspath", "line", "col"],
|
|
|
|
|
handler: UnofficialEndpoints.findTypeDefinition,
|
|
|
|
|
},
|
|
|
|
|
"/find_declaration": {
|
|
|
|
|
keys: ["abspath", "line", "col"],
|
|
|
|
|
handler: UnofficialEndpoints.findTypeDefinition,
|
|
|
|
|
},
|
|
|
|
|
"/find_implementation": {
|
|
|
|
|
keys: ["abspath", "line", "col"],
|
|
|
|
|
handler: UnofficialEndpoints.findImplementation,
|
|
|
|
|
},
|
|
|
|
|
"/find_reference": {
|
|
|
|
|
keys: ["abspath", "line", "col"],
|
|
|
|
|
handler: UnofficialEndpoints.findReference,
|
|
|
|
|
},
|
|
|
|
|
"/open_folder": {
|
|
|
|
|
keys: ["folder"],
|
|
|
|
|
handler: UnofficialEndpoints.openFolder,
|
|
|
|
|
},
|
|
|
|
|
"/get_symbol_defines_in_selected_code": {
|
|
|
|
|
keys: [],
|
|
|
|
|
handler: UnofficialEndpoints.getSymbolDefinesInSelectedCode,
|
|
|
|
|
},
|
2023-11-29 23:34:15 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let server: http.Server | null = null;
|
|
|
|
|
export async function startRpcServer() {
|
2024-01-31 23:57:57 +08:00
|
|
|
|
server = http.createServer((req, res) => {
|
|
|
|
|
const parsedUrl = new URL(req.url!, `http://${req.headers.host}`);
|
|
|
|
|
logger.channel()?.info(`request: ${parsedUrl}`);
|
|
|
|
|
if (parsedUrl.pathname === "/favicon.ico") {
|
|
|
|
|
res.writeHead(204);
|
|
|
|
|
res.end();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let params: any = {};
|
|
|
|
|
|
|
|
|
|
if (req.method === "POST") {
|
|
|
|
|
let body = "";
|
|
|
|
|
req.on("data", (chunk) => {
|
|
|
|
|
body += chunk.toString(); // 将Buffer转换为string
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
req.on("end", () => {
|
|
|
|
|
// 根据不同Content-Type,进行不同方式的解析
|
|
|
|
|
if (req.headers["content-type"] === "application/json") {
|
|
|
|
|
// 解析JSON格式的数据
|
|
|
|
|
params = JSON.parse(body);
|
|
|
|
|
|
|
|
|
|
// 处理postParams
|
|
|
|
|
} else if (
|
|
|
|
|
req.headers["content-type"] ===
|
|
|
|
|
"application/x-www-form-urlencoded"
|
|
|
|
|
) {
|
|
|
|
|
// 解析URL编码的数据
|
|
|
|
|
params = querystring.parse(body);
|
|
|
|
|
// 处理postParams
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleRequest(parsedUrl, params, res);
|
|
|
|
|
});
|
|
|
|
|
} else if (req.method === "GET") {
|
|
|
|
|
const queryParams = parsedUrl.searchParams;
|
|
|
|
|
for (let param of queryParams) {
|
|
|
|
|
params[param[0]] = param[1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleRequest(parsedUrl, params, res);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
async function handleRequest(
|
|
|
|
|
parsedUrl: URL,
|
|
|
|
|
params: any,
|
|
|
|
|
res: http.ServerResponse
|
|
|
|
|
) {
|
|
|
|
|
try {
|
|
|
|
|
let responseResult = {};
|
|
|
|
|
|
|
|
|
|
if (functionRegistry[parsedUrl.pathname]) {
|
|
|
|
|
let keysExist = true;
|
|
|
|
|
let newParameters: any[] = [];
|
|
|
|
|
for (let key of functionRegistry[parsedUrl.pathname]["keys"]) {
|
|
|
|
|
if (!params.hasOwnProperty(key)) {
|
|
|
|
|
// check whether key in functionRegistry[parsedUrl.pathname]['optional']
|
|
|
|
|
newParameters.push(undefined);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
newParameters.push(params[key]);
|
|
|
|
|
}
|
|
|
|
|
if (!keysExist) {
|
|
|
|
|
responseResult["error"] = "Missing required parameters";
|
|
|
|
|
} else {
|
|
|
|
|
responseResult["result"] = await functionRegistry[
|
|
|
|
|
parsedUrl.pathname
|
|
|
|
|
]["handler"](...newParameters);
|
|
|
|
|
if (
|
|
|
|
|
parsedUrl.pathname === "/definitions" ||
|
|
|
|
|
parsedUrl.pathname === "/references"
|
|
|
|
|
) {
|
|
|
|
|
responseResult = responseResult["result"];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
responseResult["error"] = "Function not found";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
|
|
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
|
|
|
res.end(JSON.stringify(responseResult));
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.channel()?.error(`Error: ${error}`);
|
|
|
|
|
logger.channel()?.show();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
server.listen(0, () => {
|
|
|
|
|
const address = server!.address();
|
|
|
|
|
// `address()`返回的对象包含`port`属性,它是系统分配的端口号
|
|
|
|
|
const port = typeof address === "string" ? address : address?.port;
|
|
|
|
|
logger.channel()?.info(`Server running at http://localhost:${port}/`);
|
|
|
|
|
process.env.DEVCHAT_IDE_SERVICE_URL = `http://localhost:${port}`;
|
|
|
|
|
process.env.DEVCHAT_IDE_SERVICE_PORT = `${port}`;
|
|
|
|
|
});
|
|
|
|
|
}
|