files.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. 'use strict';
  2. const Controller = require('egg').Controller;
  3. const moment = require('moment');
  4. const { sep, extname } = require('path');
  5. const fs = require('fs');
  6. const awaitWriteStream = require('await-stream-ready').write;
  7. const sendToWormhole = require('stream-wormhole');
  8. const assert = require('assert');
  9. const wxstream = require('stream');
  10. const ffmpeg = require('fluent-ffmpeg');
  11. const { BusinessError, ErrorCode } = require('naf-core').Error;
  12. class FilesController extends Controller {
  13. async upload() {
  14. const { ctx, app } = this;
  15. const { appid, catalog, item } = ctx.params;
  16. assert(appid);
  17. const stream = await ctx.getFileStream();
  18. ctx.logger.debug(stream);
  19. const rootPath = `${app.config.cdn.repos_root_path}`;
  20. const rootUrl = `${app.config.cdn.repos_root_url}`;
  21. const dirs = [ appid ];
  22. if (catalog && catalog !== '_') {
  23. const subs = catalog.split('_');
  24. dirs.push(...subs);
  25. }
  26. const saved = await this.saveFile(rootPath, dirs, stream, item);
  27. const uri = `${rootUrl}/${dirs.join('/')}/${saved.fileName}`;
  28. ctx.body = { errcode: 0, errmsg: 'ok', id: saved.id, name: saved.fileName, uri };
  29. }
  30. async saveFile(rootPath, dirs, stream, name) {
  31. const ctx = this.ctx;
  32. const ext = extname(stream.filename).toLowerCase();
  33. // TODO: 指定文件名或者按时间生成文件名
  34. // const name = moment().format('YYYYMMDDHHmmss');
  35. if (!name) name = moment().format('YYYYMMDDHHmmss');
  36. // TODO: 检查根路径是否存在,不存在则创建
  37. ctx.logger.debug('rootPath: ', rootPath);
  38. if (!fs.existsSync(rootPath)) {
  39. ctx.logger.debug('create dir: ', rootPath);
  40. fs.mkdirSync(rootPath);
  41. }
  42. // TODO: 检查分级目录是否存在,不存在则创建
  43. for (let i = 0; i < dirs.length; i++) {
  44. const p = `${rootPath}${sep}${dirs.slice(0, i + 1).join(sep)}`;
  45. if (!fs.existsSync(p)) {
  46. fs.mkdirSync(p);
  47. }
  48. }
  49. const filePath = `${rootPath}${sep}${dirs.join(sep)}${sep}`;
  50. const fileName = `${name}${ext}`;
  51. const writeStream = fs.createWriteStream(filePath + fileName);
  52. try {
  53. await awaitWriteStream(stream.pipe(writeStream));
  54. } catch (err) {
  55. await sendToWormhole(stream);
  56. throw err;
  57. }
  58. return { filePath, fileName, id: name };
  59. }
  60. async wxupload() {
  61. const { serverid, type, appid } = this.ctx.request.body;
  62. assert(serverid, 'serverid不允许为空');
  63. assert(type, 'type不允许为空');
  64. const { ctx, app } = this;
  65. const url = app.config.wx.wxdown(appid, serverid);
  66. const file = await this.ctx.curl(url);
  67. const stream = new wxstream.PassThrough();
  68. stream.end(file.data);
  69. const rootPath = `${app.config.cdn.repos_root_path}`;
  70. const rootUrl = `${app.config.cdn.repos_root_url}`;
  71. let uri;
  72. // 判断类型 0、图片 1、音频 2、视频
  73. if (type === '0') {
  74. const dirs = [ 'wximage' ];
  75. const saved = await this.wxsaveFile(rootPath, dirs, stream, '.jpg');
  76. uri = `${rootUrl}/${dirs.join('/')}/${saved.fileName}`;
  77. } else if (type === '1') {
  78. const dirs = [ 'wxadio' ];
  79. const saved = await this.wxsaveFile(rootPath, dirs, stream, '.amr');
  80. // 音频时如果需要使用转码,以下调用ffmpeg进行转码处理
  81. // const hz = '.mp3';
  82. const resultname = `${saved.id}.amr`;
  83. // const ffurl = `${saved.filePath}${resultname}`;
  84. // if (!ffmpeg) throw new BusinessError(ErrorCode.SERVICE_FAULT, '转换失败');
  85. // new ffmpeg({ source: `${saved.filePath}${saved.fileName}` })
  86. // .saveToFile(ffurl, function(retcode, error) {
  87. // })
  88. // .on('end', function() {
  89. // // 在这里处理完成后的结果
  90. // console.log('Finished processing');
  91. // });
  92. uri = `${rootUrl}/${dirs.join('/')}/${resultname}`;
  93. } else if (type === '2') {
  94. const dirs = [ 'wxvideo' ];
  95. const saved = await this.wxsaveFile(rootPath, dirs, stream, '');
  96. uri = `${rootUrl}/${dirs.join('/')}/${saved.fileName}`;
  97. }
  98. ctx.body = { errcode: 0, errmsg: 'ok', uri };
  99. }
  100. async wxsaveFile(rootPath, dirs, stream, ext) {
  101. const ctx = this.ctx;
  102. // TODO: 指定文件名或者按时间生成文件名
  103. const name = moment().format('YYYYMMDDHHmmss');
  104. // TODO: 检查根路径是否存在,不存在则创建
  105. ctx.logger.debug('rootPath: ', rootPath);
  106. if (!fs.existsSync(rootPath)) {
  107. ctx.logger.debug('create dir: ', rootPath);
  108. fs.mkdirSync(rootPath);
  109. }
  110. // TODO: 检查分级目录是否存在,不存在则创建
  111. for (let i = 0; i < dirs.length; i++) {
  112. const p = `${rootPath}${sep}${dirs.slice(0, i + 1).join(sep)}`;
  113. if (!fs.existsSync(p)) {
  114. fs.mkdirSync(p);
  115. }
  116. }
  117. const filePath = `${rootPath}${sep}${dirs.join(sep)}${sep}`;
  118. const fileName = `${name}${ext}`;
  119. const writeStream = fs.createWriteStream(filePath + fileName);
  120. try {
  121. await awaitWriteStream(stream.pipe(writeStream));
  122. } catch (err) {
  123. await sendToWormhole(stream);
  124. throw err;
  125. }
  126. return { filePath, fileName, id: name };
  127. }
  128. async serverUpload() {
  129. console.log('in function:');
  130. const { ctx, app } = this;
  131. const body = ctx.request.body;
  132. const { name, uri, extension, code } = body;
  133. const path = uri;
  134. if (!path) {
  135. return this.getErrorReturn('缺少文件存储路径');
  136. }
  137. const rootPath = `${app.config.cdn.repos_root_path}`;
  138. const rootUrl = `${app.config.cdn.repos_root_url}`;
  139. if (!fs.existsSync(rootPath)) {
  140. ctx.logger.debug('create dir: ', rootPath);
  141. fs.mkdirSync(rootPath);
  142. }
  143. const dirs = path.split('/');
  144. dirs.pop();
  145. // 检查路径是否存在,不存在就创建
  146. let realPath = rootPath;
  147. const realPathArray = [];
  148. for (const p of dirs) {
  149. const children = p.split('_');
  150. for (const c of children) {
  151. realPath = `${realPath}${sep}${c}`;
  152. if (!fs.existsSync(realPath)) {
  153. fs.mkdirSync(realPath);
  154. }
  155. realPathArray.push(c);
  156. }
  157. }
  158. const filePath = `${rootUrl}/${realPathArray.join('/')}`;
  159. const fileName = `${name || new Date().getTime()}.${extension}`;
  160. try {
  161. const base64Data = code.replace(/^data:image\/\w+;base64,/, '');
  162. const dataBuffer = Buffer(base64Data, 'base64');
  163. await fs.writeFileSync(`${realPath}${sep}${fileName}`, Buffer(dataBuffer, 'base64'));
  164. } catch (error) {
  165. throw error;
  166. }
  167. let returnUri = `${filePath}/${fileName}`;
  168. while (returnUri.indexOf('//')) {
  169. returnUri = returnUri.replace('//', '/');
  170. }
  171. this.ctx.body = this.getSuccessReturn({ uri: returnUri, id: fileName });
  172. }
  173. getErrorReturn(message) {
  174. return { errcode: -1, errmsg: message || '程序发生错误' };
  175. }
  176. getSuccessReturn(data) {
  177. return { errcode: 0, errmsg: 'ok', data };
  178. }
  179. }
  180. module.exports = FilesController;