server.js 15 KB

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