LjFileHelper.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. var request = require('request');
  2. var fs = require('fs');
  3. var ffmpeg = require('fluent-ffmpeg');
  4. var ljConst = require("../common/LjConst.js");
  5. var path = require('path');
  6. var logHelper = require("./LjLogHelper");
  7. var apiHelper = require("../helper/LjApiHelper");
  8. var httpHelper = require("../helper/LjHttpHelper");
  9. /**
  10. * The helper of file
  11. */
  12. class LjFileHelper
  13. {
  14. /**
  15. * Download file
  16. * @param fileUrl the file url
  17. * @returns {boolean}
  18. */
  19. static downloadFile(fileUrl,opt)
  20. {
  21. //获取文件属性对象
  22. var filePropObj = this.getFileProperty(fileUrl);
  23. if (filePropObj == null)
  24. {
  25. return false;
  26. }
  27. //视频处理
  28. if (filePropObj.fileType == ljConst.VIDEO_TYPE_M3U8)
  29. {
  30. //未加密视频本地存储路径
  31. var localFileDir = filePropObj.folderDir + filePropObj.fileName + ".mp4"
  32. //M3U8视频转换MP4
  33. ffmpeg(fileUrl).format(ljConst.VIDEO_TYPE_MP4)
  34. .on('start', function (err)
  35. {
  36. logHelper.info("Starting down video:" + fileUrl);
  37. })
  38. .on('error', function (err)
  39. {
  40. logHelper.error("Succeeded to down video[" + fileUrl + "]: " + err.message);
  41. })
  42. .on('end', function ()
  43. {
  44. //加密视频存储路径
  45. let localFileDirNew = filePropObj.folderDir + filePropObj.fileName + "_new" + ".mp4"
  46. logHelper.info("Succeeded to down video:" + localFileDirNew);
  47. //加密存储
  48. LjFileHelper.writeEncryptedStream(localFileDir, localFileDirNew,function(){
  49. LjFileHelper.updateDownloadResSize(opt);
  50. });
  51. logHelper.info("Succeeded to encrypt video:" + localFileDirNew);
  52. //删除文件(加密存储完成后删除未加密文件)
  53. fs.unlink(localFileDir, function (err)
  54. {
  55. if (err)
  56. {
  57. //删除失败
  58. logHelper.info("Failed to delete video[" + err.message + "]:" + localFileDir);
  59. throw err;
  60. }
  61. else
  62. {
  63. logHelper.info('Succeeded to delete video:' + localFileDir)
  64. }
  65. })
  66. })
  67. .save(localFileDir);
  68. }//有声读物处理
  69. else if (filePropObj.fileType == ljConst.VIDEO_TYPE_MP3)
  70. {
  71. //未加密有声读物本地存储地址
  72. var localFileDir = filePropObj.folderDir + filePropObj.fileName + "." + filePropObj.fileType;
  73. //读取有声读物
  74. request(fileUrl).pipe(fs.createWriteStream(localFileDir)).on('close', function ()
  75. {
  76. //加密有声读物存储地址
  77. var localFileDirNew = filePropObj.folderDir + filePropObj.fileName + "_new." + filePropObj.fileType;
  78. logHelper.info("Succeeded to down audio:" + localFileDirNew);
  79. //加密有声读物
  80. LjFileHelper.writeEncryptedStream(localFileDir, localFileDirNew,function(){
  81. LjFileHelper.updateDownloadResSize(opt);
  82. });
  83. logHelper.info("Succeeded to image audio:" + localFileDirNew);
  84. //删除文件(加密存储完成后删除未加密文件)
  85. fs.unlink(localFileDir, function (err)
  86. {
  87. if (err)
  88. {
  89. //删除失败
  90. logHelper.erro("Failed to delete audio[" + err.message + "]:" + localFileDir);
  91. throw err;
  92. }
  93. else
  94. {
  95. logHelper.info('Succeeded to delete audio:' + localFileDir)
  96. }
  97. })
  98. });
  99. }//图片处理
  100. else
  101. {
  102. //未加密图片本地存储地址
  103. var localFileDir = filePropObj.folderDir + filePropObj.fileName + "." + filePropObj.fileType;
  104. //读取图片
  105. request(fileUrl).pipe(fs.createWriteStream(localFileDir)).on('close', function ()
  106. {
  107. //加密图片存储地址
  108. var localFileDirNew = filePropObj.folderDir + filePropObj.fileName + "_new." + filePropObj.fileType;
  109. logHelper.info("Succeeded to down image:" + localFileDirNew);
  110. //加密图片
  111. LjFileHelper.writeEncryptedStream(localFileDir, localFileDirNew,function(){
  112. LjFileHelper.updateDownloadResSize(opt);
  113. });
  114. logHelper.info("Succeeded to image image:" + localFileDirNew);
  115. //删除文件(加密存储完成后删除未加密文件)
  116. fs.unlink(localFileDir, function (err)
  117. {
  118. if (err)
  119. {
  120. //删除失败
  121. logHelper.error("Failed to delete image[" + err.message + "]:" + localFileDir);
  122. throw err;
  123. }
  124. else
  125. {
  126. logHelper.info('Succeeded to delete image:' + localFileDir)
  127. }
  128. })
  129. });
  130. }
  131. }
  132. /**
  133. * Delete file
  134. * @param fileUrl the file url
  135. * @returns {boolean}
  136. */
  137. static delFile(fileUrl)
  138. {
  139. //获取文件属性对象
  140. var filePropObj = this.getFileProperty(fileUrl);
  141. if (filePropObj == null)
  142. {
  143. return false;
  144. }
  145. //视频处理
  146. if (filePropObj.fileType == ljConst.VIDEO_TYPE_M3U8)
  147. {
  148. //加密视频存储路径
  149. let localFileDirNew = filePropObj.folderDir + filePropObj.fileName + "_new" + ".mp4"
  150. logHelper.info("Succeeded to down video:" + localFileDirNew);
  151. //删除加密文件
  152. fs.unlink(localFileDirNew, function (err)
  153. {
  154. if (err)
  155. {
  156. //删除失败
  157. logHelper.info("Failed to delete video[" + err.message + "]:" + localFileDir);
  158. throw err;
  159. }
  160. else
  161. {
  162. logHelper.info('Succeeded to delete video:' + localFileDir)
  163. }
  164. })
  165. }//图片处理
  166. else
  167. {
  168. //加密图片存储地址
  169. var localFileDirNew = filePropObj.folderDir + filePropObj.fileName + "_new." + filePropObj.fileType;
  170. logHelper.info("Succeeded to down image:" + localFileDirNew);
  171. //删除加密文件
  172. fs.unlink(localFileDirNew, function (err)
  173. {
  174. if (err)
  175. {
  176. //删除失败
  177. logHelper.erro("Failed to delete image[" + err.message + "]:" + localFileDir);
  178. throw err;
  179. }
  180. else
  181. {
  182. logHelper.info('Succeeded to delete image:' + localFileDir)
  183. }
  184. })
  185. }
  186. }
  187. /**
  188. * Gets file directory
  189. * @param fileName the file name
  190. * @returns {*|string} the file directory
  191. */
  192. static getFileDir(fileName)
  193. {
  194. var fileType = fileName.split(".")[1]
  195. var newFileDir = "";
  196. if (fileType == "m3u8")
  197. {
  198. fileName = fileName.replace(".m3u8", "_new.mp4")
  199. newFileDir = ljConst.BASE_DIR + fileName.replace(/\*/g, '\\');
  200. }
  201. else
  202. {
  203. fileName = fileName.replace(".", "_new.")
  204. newFileDir = ljConst.BASE_DIR + fileName.replace(/\*/g, '\\');
  205. }
  206. return newFileDir;
  207. }
  208. /**
  209. * Makes directory
  210. * @param dirname the directory name
  211. * @returns {boolean} true or false
  212. */
  213. static mkdirsSync(dirname)
  214. {
  215. if (fs.existsSync(dirname))
  216. {
  217. return true;
  218. }
  219. else
  220. {
  221. if (this.mkdirsSync(path.dirname(dirname)))
  222. {
  223. fs.mkdirSync(dirname);
  224. return true;
  225. }
  226. }
  227. }
  228. /**
  229. * Gets the file property object
  230. * @param fileUrl the file URL
  231. * @returns {null}
  232. */
  233. static getFileProperty(fileUrl)
  234. {
  235. /*--文件夹目录-Begin--*/
  236. var folderDir = ljConst.BASE_DIR;
  237. var splitArr = fileUrl.split('/')
  238. var arrLen = splitArr.length;
  239. for (var i = 3; i < arrLen - 1; i++)
  240. {
  241. folderDir += splitArr[i] + "\\";
  242. }
  243. //创建文件夹目录
  244. this.mkdirsSync(folderDir);
  245. var filePropObj = {};
  246. filePropObj.folderDir = folderDir;
  247. //获取文件名称
  248. filePropObj.fileName = splitArr[arrLen - 1].split(".")[0];
  249. //获取文件类型
  250. filePropObj.fileType = splitArr[arrLen - 1].split(".")[1];
  251. /*--文件夹目录-Begin--*/
  252. return filePropObj;
  253. }
  254. /**
  255. * Gets the file property object
  256. * @param fileUrl the file URL
  257. * @returns {null}
  258. */
  259. static getFilePropertyNoMkdir(fileUrl)
  260. {
  261. /*--文件夹目录-Begin--*/
  262. var folderDir = ljConst.BASE_DIR;
  263. var splitArr = fileUrl.split('/')
  264. var arrLen = splitArr.length;
  265. for (var i = 3; i < arrLen - 1; i++)
  266. {
  267. folderDir += splitArr[i] + "\\";
  268. }
  269. var filePropObj = {};
  270. filePropObj.folderDir = folderDir;
  271. //获取文件名称
  272. filePropObj.fileName = splitArr[arrLen - 1].split(".")[0];
  273. //获取文件类型
  274. filePropObj.fileType = splitArr[arrLen - 1].split(".")[1];
  275. /*--文件夹目录-Begin--*/
  276. return filePropObj;
  277. }
  278. static Encrypted(c)
  279. {
  280. var b = '';
  281. for (var i = 0; i < c.length; i++)
  282. {
  283. var ch = c[i];
  284. if (ch == '0')
  285. {
  286. ch = 'f';
  287. }
  288. else if (ch == 'f')
  289. {
  290. ch = '0';
  291. }
  292. b = b + ch;
  293. //console.log(ch);
  294. }
  295. return b;
  296. }
  297. static Decrypted(c)
  298. {
  299. var b = '';
  300. for (var i = 0; i < c.length; i++)
  301. {
  302. var ch = c[i];
  303. if (ch == 'f')
  304. {
  305. ch = '0';
  306. }
  307. else if (ch == '0')
  308. {
  309. ch = 'f';
  310. }
  311. b = b + ch;
  312. //console.log(ch);
  313. }
  314. return b;
  315. }
  316. /**
  317. * Writes encrypted content, which is read from given source file, into given dest file
  318. * @param fSrc the source file
  319. * @param fDest the dest file
  320. */
  321. static writeEncryptedStream(fSrc, fDest,callback)
  322. {
  323. var rs = fs.createReadStream(fSrc);
  324. var ws = fs.createWriteStream(fDest);
  325. rs.on('data', function (chunk)
  326. {
  327. let b = new Buffer(chunk, 'hex');
  328. //console.log(b);
  329. let c = b.toString('hex');
  330. c = LjFileHelper.encryptedContent(c);
  331. let d = Buffer.from(c, 'hex');
  332. ws.write(d);
  333. });
  334. rs.on('end', function ()
  335. {
  336. ws.end();
  337. logHelper.info('Succeeded in writing into encrypted stream[' + fDest + '].');
  338. callback();
  339. });
  340. rs.on('error', function (err)
  341. {
  342. logHelper.error(err.stack);
  343. });
  344. }
  345. /**
  346. * Encrypts the content
  347. * @param c the content to be encrypted
  348. * @return the encrypted content
  349. */
  350. static encryptedContent(c)
  351. {
  352. var b = '';
  353. for (var i = 0; i < c.length; i++)
  354. {
  355. var ch = c[i];
  356. if (ch == '0')
  357. {
  358. ch = 'f';
  359. }
  360. else if (ch == 'f')
  361. {
  362. ch = '0';
  363. }
  364. else if (ch == '1')
  365. {
  366. ch = 'e';
  367. }
  368. else if (ch == 'e')
  369. {
  370. ch = '1';
  371. }
  372. else if (ch == '2')
  373. {
  374. ch = 'd';
  375. }
  376. else if (ch == 'd')
  377. {
  378. ch = '2';
  379. }
  380. else if (ch == '3')
  381. {
  382. ch = 'c';
  383. }
  384. else if (ch == 'c')
  385. {
  386. ch = '3';
  387. }
  388. b = b + ch;
  389. //console.log(ch);
  390. }
  391. return b;
  392. }
  393. /**
  394. * Decrypts the encrypted content
  395. * @param c the encrypted content
  396. * @return the decrypted content
  397. */
  398. static decryptedContent(c)
  399. {
  400. var b = '';
  401. for (var i = 0; i < c.length; i++)
  402. {
  403. var ch = c[i];
  404. if (ch == 'f')
  405. {
  406. ch = '0';
  407. }
  408. else if (ch == '0')
  409. {
  410. ch = 'f';
  411. }
  412. else if (ch == 'e')
  413. {
  414. ch = '1';
  415. }
  416. else if (ch == '1')
  417. {
  418. ch = 'e';
  419. }
  420. else if (ch == 'd')
  421. {
  422. ch = '2';
  423. }
  424. else if (ch == '2')
  425. {
  426. ch = 'd';
  427. }
  428. else if (ch == 'c')
  429. {
  430. ch = '3';
  431. }
  432. else if (ch == '3')
  433. {
  434. ch = 'c';
  435. }
  436. b = b + ch;
  437. //console.log(ch);
  438. }
  439. return b;
  440. }
  441. /**
  442. * Reads decrypted content, which is read from given encrypted file, into HTTP response stream
  443. * @param res the HTTP response stream
  444. * @param fDest the encrypted file
  445. */
  446. static readDecryptedStream(res, fDest, contentType)
  447. {
  448. res.writeHead(200, {'Content-Type': contentType});
  449. var rs = fs.createReadStream(fDest);
  450. rs.on('data', function (chunk)
  451. {
  452. let b = new Buffer(chunk, 'hex');
  453. let c = b.toString('hex');
  454. c = LjFileHelper.decryptedContent(c);
  455. let d = Buffer.from(c, 'hex');
  456. res.write(d);
  457. });
  458. rs.on('end', function ()
  459. {
  460. res.end();
  461. logHelper.log('Succeeded in reading from decrypted stream[' + fDest + '].');
  462. });
  463. rs.on('error', function (err)
  464. {
  465. logHelper.log(err.stack);
  466. });
  467. }
  468. static updateDownloadResSize(opt)
  469. {
  470. //return false;
  471. opt.url = apiHelper.getApiForUpdateResSize(opt.lessonId);
  472. opt.method = "PUT";
  473. opt.path = "/callback/download/update/resource/size";
  474. httpHelper.request(opt, function (error, res, body)
  475. {
  476. logHelper.info(body);
  477. var retObj = JSON.parse(body);
  478. logHelper.debug(retObj);
  479. if (retObj.code == 200)
  480. {
  481. logHelper.info("Succeed to call api[" + opt.path + "]");
  482. return true;
  483. }
  484. else
  485. {
  486. logHelper.error("Failed to call api[" + opt.path + "],caused by error[" + retObj.message + "]");
  487. return false;
  488. }
  489. });
  490. }
  491. /**
  492. * Is video
  493. * @param dir the directory
  494. * @returns {boolean}
  495. */
  496. isVideo(dir)
  497. {
  498. if (dir == "")
  499. {
  500. return false;
  501. }
  502. var fileType = dir.split(".")[1];
  503. if ("m3u8" == fileType)
  504. {
  505. return true;
  506. }
  507. return false;
  508. }
  509. }
  510. module.exports = LjFileHelper;