server.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. const http = require("http");
  2. const querystring = require("querystring");
  3. const url = require("url");
  4. const fs = require("fs");
  5. const path = require("path");
  6. const { app, dialog } = require("electron");
  7. const XLSX = require("xlsx");
  8. const formidable = require("formidable");
  9. const express = require("express");
  10. const multer = require("multer");
  11. const cors = require("cors");
  12. function travel(dir, callback) {
  13. fs.readdirSync(dir).forEach((file) => {
  14. const pathname = path.join(dir, file);
  15. if (fs.statSync(pathname).isDirectory()) {
  16. travel(pathname, callback);
  17. } else {
  18. callback(pathname);
  19. }
  20. });
  21. }
  22. function compare(p) {
  23. //这是比较函数
  24. return function (m, n) {
  25. let a = m[p];
  26. let b = n[p];
  27. return b - a; //降序
  28. };
  29. }
  30. function getDir() {
  31. if (__dirname.indexOf("app") >= 0 && __dirname.indexOf("sources") >= 0) {
  32. if (process.platform == "darwin") {
  33. return app.getPath("userData");
  34. } else {
  35. return path.join(__dirname, "../../..");
  36. }
  37. } else {
  38. return __dirname;
  39. }
  40. }
  41. function getEasySpiderLocation() {
  42. if (__dirname.indexOf("app") >= 0 && __dirname.indexOf("sources") >= 0) {
  43. if (process.platform == "darwin") {
  44. return path.join(__dirname, "../../../");
  45. } else {
  46. return path.join(__dirname, "../../../");
  47. }
  48. } else {
  49. return __dirname;
  50. }
  51. }
  52. if (!fs.existsSync(path.join(getDir(), "tasks"))) {
  53. fs.mkdirSync(path.join(getDir(), "tasks"));
  54. }
  55. if (!fs.existsSync(path.join(getDir(), "execution_instances"))) {
  56. fs.mkdirSync(path.join(getDir(), "execution_instances"));
  57. }
  58. if (!fs.existsSync(path.join(getDir(), "config.json"))) {
  59. // Generate config.json
  60. fs.writeFileSync(
  61. path.join(getDir(), "config.json"),
  62. JSON.stringify({
  63. webserver_address: "http://localhost",
  64. webserver_port: 8074,
  65. user_data_folder: "./user_data",
  66. debug: false,
  67. lang: "-",
  68. copyright: 0,
  69. sys_arch: require("os").arch(),
  70. mysql_config_path: "./mysql_config.json",
  71. absolute_user_data_folder:
  72. "D:\\Document\\Projects\\EasySpider\\ElectronJS\\user_data",
  73. })
  74. );
  75. }
  76. exports.getDir = getDir;
  77. exports.getEasySpiderLocation = getEasySpiderLocation;
  78. FileMimes = JSON.parse(
  79. fs.readFileSync(path.join(__dirname, "mime.json")).toString()
  80. );
  81. const fileServer = express();
  82. const upload = multer({ dest: path.join(getDir(), "Data/") });
  83. fileServer.use(cors());
  84. fileServer.post("/excelUpload", upload.single("file"), (req, res) => {
  85. let workbook = XLSX.readFile(req.file.path);
  86. let sheet_name_list = workbook.SheetNames;
  87. let data = XLSX.utils.sheet_to_json(workbook.Sheets[sheet_name_list[0]]);
  88. let result = data.reduce((acc, obj) => {
  89. Object.keys(obj).forEach((key) => {
  90. if (!acc[key]) {
  91. acc[key] = [];
  92. }
  93. acc[key].push(obj[key]);
  94. });
  95. return acc;
  96. }, {});
  97. // console.log(data);
  98. // delete file after reading
  99. fs.unlink(req.file.path, (err) => {
  100. if (err) {
  101. console.error(err);
  102. return;
  103. }
  104. // file removed
  105. });
  106. res.send(JSON.stringify(result));
  107. });
  108. fileServer.listen(8075, () => {
  109. console.log("Server listening on http://localhost:8075");
  110. });
  111. exports.start = function (port = 8074) {
  112. http
  113. .createServer(function (req, res) {
  114. let body = "";
  115. res.setHeader("Access-Control-Allow-Origin", "*"); // 设置可访问的源
  116. // 解析参数
  117. const pathName = url.parse(req.url).pathname;
  118. const safeBase = path.join(__dirname, "src");
  119. const safeJoin = (base, target) => {
  120. const targetPath = "." + path.posix.normalize("/" + target);
  121. return path.join(base, targetPath);
  122. };
  123. if (pathName == "/excelUpload" && req.method.toLowerCase() === "post") {
  124. // // parse a file upload
  125. // let form = new formidable.IncomingForm();
  126. // // Set the max file size
  127. // form.maxFileSize = 200 * 1024 * 1024; // 200MB
  128. // form.parse(req, function (err, fields, files) {
  129. // console.log("excelUpload")
  130. // console.log(err, fields, files);
  131. // let oldpath = files.file.path;
  132. // let workbook = XLSX.readFile(oldpath);
  133. // let sheet_name_list = workbook.SheetNames;
  134. // let data = XLSX.utils.sheet_to_json(workbook.Sheets[sheet_name_list[0]]);
  135. // console.log(data);
  136. // res.end('File uploaded and read successfully.');
  137. // });
  138. } else if (pathName.indexOf(".") < 0) {
  139. //如果没有后缀名, 则为后台请求
  140. res.writeHead(200, { "Content-Type": "application/json" });
  141. }
  142. // else if(pathName.indexOf("index.html") >= 0) {
  143. // fs.readFile(path.join(__dirname,"src", pathName), async (err, data) => {
  144. // if (err) {
  145. // res.writeHead(404, { 'Content-Type': 'text/html;charset="utf-8"' })
  146. // res.end(err.message)
  147. // return;
  148. // }
  149. // if (!err) {
  150. // // 3. 针对不同的文件返回不同的内容头
  151. // let extname = path.extname(pathName);
  152. // let mime = FileMimes[extname]
  153. // res.writeHead(200, { 'Content-Type': mime + ';charset="utf-8"' })
  154. // res.end(data);
  155. // return;
  156. // }
  157. // })
  158. // }
  159. else {
  160. //如果有后缀名, 则为前端请求
  161. // console.log(path.join(__dirname,"src/taskGrid", pathName));
  162. const filePath = safeJoin(safeBase, pathName);
  163. if (!filePath.startsWith(safeBase)) {
  164. res.writeHead(400, { "Content-Type": 'text/html;charset="utf-8"' });
  165. res.end("Invalid path");
  166. return;
  167. }
  168. fs.readFile(
  169. filePath,
  170. async (err, data) => {
  171. if (err) {
  172. res.writeHead(404, {
  173. "Content-Type": 'text/html;charset="utf-8"',
  174. });
  175. res.end(err.message);
  176. return;
  177. }
  178. if (!err) {
  179. // 3. 针对不同的文件返回不同的内容头
  180. let extname = path.extname(pathName);
  181. let mime = FileMimes[extname];
  182. res.writeHead(200, { "Content-Type": mime + ';charset="utf-8"' });
  183. res.end(data);
  184. return;
  185. }
  186. }
  187. );
  188. }
  189. req.on("data", function (chunk) {
  190. body += chunk;
  191. });
  192. req.on("end", function () {
  193. // 设置响应头部信息及编码
  194. if (pathName == "/queryTasks") {
  195. //查询所有服务信息,只包括id和服务名称
  196. output = [];
  197. travel(path.join(getDir(), "tasks"), function (pathname) {
  198. const data = fs.readFileSync(pathname, "utf8");
  199. let stat = fs.statSync(pathname, "utf8");
  200. // parse JSON string to JSON object
  201. // console.log("\n\n\n\n\n", pathname, '\n\n\n\n\n\n');
  202. if (pathname.indexOf(".json") >= 0) {
  203. const task = JSON.parse(data);
  204. let item = {
  205. id: task.id,
  206. name: task.name,
  207. url: task.url,
  208. mtime: stat.mtime,
  209. links: task.links,
  210. desc: task.desc,
  211. };
  212. if (item.id != -2) {
  213. output.push(item);
  214. }
  215. }
  216. });
  217. output.sort(compare("mtime"));
  218. res.write(JSON.stringify(output));
  219. res.end();
  220. } else if (pathName == "/queryOSVersion") {
  221. res.write(
  222. JSON.stringify({ version: process.platform, bit: process.arch })
  223. );
  224. res.end();
  225. } else if (pathName == "/queryExecutionInstances") {
  226. //查询所有服务信息,只包括id和服务名称
  227. output = [];
  228. travel(
  229. path.join(getDir(), "execution_instances"),
  230. function (pathname) {
  231. const data = fs.readFileSync(pathname, "utf8");
  232. // parse JSON string to JSON object
  233. const task = JSON.parse(data);
  234. let item = {
  235. id: task.id,
  236. name: task.name,
  237. url: task.url,
  238. };
  239. if (item.id != -2) {
  240. output.push(item);
  241. }
  242. }
  243. );
  244. res.write(JSON.stringify(output));
  245. res.end();
  246. } else if (pathName == "/queryTask") {
  247. let params = url.parse(req.url, true).query;
  248. try {
  249. let tid = parseInt(params.id);
  250. const data = fs.readFileSync(
  251. path.join(getDir(), `tasks/${tid}.json`),
  252. "utf8"
  253. );
  254. // parse JSON string to JSON object
  255. res.write(data);
  256. res.end();
  257. } catch (error) {
  258. res.write(
  259. JSON.stringify({
  260. error: "Cannot find task based on specified task ID.",
  261. })
  262. );
  263. res.end();
  264. }
  265. } else if (pathName == "/queryExecutionInstance") {
  266. let params = url.parse(req.url, true).query;
  267. try {
  268. let tid = parseInt(params.id);
  269. const data = fs.readFileSync(
  270. path.join(getDir(), `execution_instances/${tid}.json`),
  271. "utf8"
  272. );
  273. // parse JSON string to JSON object
  274. res.write(data);
  275. res.end();
  276. } catch (error) {
  277. res.write(
  278. JSON.stringify({
  279. error:
  280. "Cannot find execution instance based on specified execution ID.",
  281. })
  282. );
  283. res.end();
  284. }
  285. } else if (pathName == "/") {
  286. res.write("Hello World!", "utf8");
  287. res.end();
  288. } else if (pathName == "/deleteTask") {
  289. let params = url.parse(req.url, true).query;
  290. try {
  291. let tid = parseInt(params.id);
  292. let data = fs.readFileSync(
  293. path.join(getDir(), `tasks/${tid}.json`),
  294. "utf8"
  295. );
  296. data = JSON.parse(data);
  297. data.id = -2;
  298. data = JSON.stringify(data);
  299. // write JSON string to a file
  300. fs.writeFile(
  301. path.join(getDir(), `tasks/${tid}.json`),
  302. data,
  303. (err) => {
  304. if (err) {
  305. throw err;
  306. }
  307. }
  308. );
  309. res.write(
  310. JSON.stringify({ success: "Task has been deleted successfully." })
  311. );
  312. res.end();
  313. } catch (error) {
  314. res.write(
  315. JSON.stringify({
  316. error: "Cannot find task based on specified task ID.",
  317. })
  318. );
  319. res.end();
  320. }
  321. } else if (pathName == "/manageTask") {
  322. body = querystring.parse(body);
  323. data = JSON.parse(body.params);
  324. let id = data["id"];
  325. if (data["id"] == -1) {
  326. file_names = [];
  327. fs.readdirSync(path.join(getDir(), "tasks")).forEach((file) => {
  328. try {
  329. if (file.split(".")[1] == "json") {
  330. file_names.push(parseInt(file.split(".")[0]));
  331. }
  332. } catch (error) {}
  333. });
  334. if (file_names.length == 0) {
  335. id = 0;
  336. } else {
  337. id = Math.max(...file_names) + 1;
  338. }
  339. data["id"] = id;
  340. // write JSON string to a fil
  341. }
  342. if (data["outputFormat"] == "mysql") {
  343. let mysql_config_path = path.join(getDir(), "mysql_config.json");
  344. // 检测文件是否存在
  345. fs.access(mysql_config_path, fs.F_OK, (err) => {
  346. if (err) {
  347. console.log("File does not exist. Creating...");
  348. // 文件不存在,创建文件
  349. const config = {
  350. host: "localhost",
  351. port: 3306,
  352. username: "your_username",
  353. password: "your_password",
  354. database: "your_database",
  355. };
  356. fs.writeFile(
  357. mysql_config_path,
  358. JSON.stringify(config, null, 4),
  359. (err) => {
  360. if (err) throw err;
  361. console.log("File is created successfully.");
  362. }
  363. );
  364. } else {
  365. console.log("File exists.");
  366. }
  367. });
  368. }
  369. data = JSON.stringify(data);
  370. // write JSON string to a file
  371. fs.writeFile(
  372. path.join(getDir(), `tasks/${id}.json`),
  373. data,
  374. (err) => {}
  375. );
  376. res.write(id.toString(), "utf8");
  377. res.end();
  378. } else if (pathName == "/invokeTask") {
  379. body = querystring.parse(body);
  380. let data = JSON.parse(body.params);
  381. let id = body.id;
  382. let task = fs.readFileSync(
  383. path.join(getDir(), `tasks/${id}.json`),
  384. "utf8"
  385. );
  386. task = JSON.parse(task);
  387. try {
  388. task["links"] = data["urlList_0"];
  389. if (task["links"] == undefined) {
  390. task["links"] = "about:blank";
  391. }
  392. } catch (error) {
  393. task["links"] = "about:blank";
  394. }
  395. for (const [key, value] of Object.entries(data)) {
  396. for (let i = 0; i < task["inputParameters"].length; i++) {
  397. if (key === task["inputParameters"][i]["name"]) {
  398. // 能调用
  399. const nodeId = parseInt(task["inputParameters"][i]["nodeId"]);
  400. const node = task["graph"][nodeId];
  401. if (node["option"] === 1) {
  402. node["parameters"]["links"] = value;
  403. } else if (node["option"] === 4) {
  404. node["parameters"]["value"] = value;
  405. } else if (
  406. node["option"] === 8 &&
  407. node["parameters"]["loopType"] === 0
  408. ) {
  409. node["parameters"]["exitCount"] = parseInt(value);
  410. } else if (node["option"] === 8) {
  411. node["parameters"]["textList"] = value;
  412. }
  413. break;
  414. }
  415. }
  416. }
  417. let file_names = [];
  418. fs.readdirSync(path.join(getDir(), "execution_instances")).forEach(
  419. (file) => {
  420. try {
  421. if (file.split(".")[1] == "json") {
  422. file_names.push(parseInt(file.split(".")[0]));
  423. }
  424. console.log(file);
  425. } catch (error) {}
  426. }
  427. );
  428. let eid = 0;
  429. if (file_names.length != 0) {
  430. eid = Math.max(...file_names) + 1;
  431. }
  432. if (body["EID"] != "" && body["EID"] != undefined) {
  433. //覆盖原有的执行实例
  434. eid = parseInt(body["EID"]);
  435. }
  436. task["id"] = eid;
  437. task = JSON.stringify(task);
  438. fs.writeFile(
  439. path.join(getDir(), `execution_instances/${eid}.json`),
  440. task,
  441. (err) => {}
  442. );
  443. res.write(eid.toString(), "utf8");
  444. res.end();
  445. } else if (pathName == "/getConfig") {
  446. let config_file = fs.readFileSync(
  447. path.join(getDir(), `config.json`),
  448. "utf8"
  449. );
  450. config_file = JSON.parse(config_file);
  451. let lang = config_file["lang"];
  452. if(lang == undefined){
  453. lang = "-";
  454. }
  455. res.write(JSON.stringify(config_file));
  456. res.end();
  457. } else if (pathName == "/setUserDataFolder") {
  458. let config = fs.readFileSync(
  459. path.join(getDir(), `config.json`),
  460. "utf8"
  461. );
  462. config = JSON.parse(config);
  463. body = querystring.parse(body);
  464. config["user_data_folder"] = body["user_data_folder"];
  465. config = JSON.stringify(config);
  466. fs.writeFile(path.join(getDir(), `config.json`), config, (err) => {});
  467. res.write(
  468. JSON.stringify({
  469. success: "User data folder has been set successfully.",
  470. })
  471. );
  472. res.end();
  473. }
  474. });
  475. })
  476. .listen(port);
  477. console.log("Server has started.");
  478. };