server.js 16 KB

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