mock平台

interfaceSyncUtils.js 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. const schedule = require('node-schedule');
  2. const openController = require('controllers/open.js');
  3. const projectModel = require('models/project.js');
  4. const syncModel = require('./syncModel.js');
  5. const tokenModel = require('models/token.js');
  6. const yapi = require('yapi.js')
  7. const sha = require('sha.js');
  8. const md5 = require('md5');
  9. const { getToken } = require('utils/token');
  10. const jobMap = new Map();
  11. class syncUtils {
  12. constructor(ctx) {
  13. yapi.commons.log("-------------------------------------swaggerSyncUtils constructor-----------------------------------------------");
  14. this.ctx = ctx;
  15. this.openController = yapi.getInst(openController);
  16. this.syncModel = yapi.getInst(syncModel);
  17. this.tokenModel = yapi.getInst(tokenModel)
  18. this.projectModel = yapi.getInst(projectModel);
  19. this.init()
  20. }
  21. //初始化定时任务
  22. async init() {
  23. let allSyncJob = await this.syncModel.listAll();
  24. for (let i = 0, len = allSyncJob.length; i < len; i++) {
  25. let syncItem = allSyncJob[i];
  26. if (syncItem.is_sync_open) {
  27. this.addSyncJob(syncItem.project_id, syncItem.sync_cron, syncItem.sync_json_url, syncItem.sync_mode, syncItem.uid);
  28. }
  29. }
  30. }
  31. /**
  32. * 新增同步任务.
  33. * @param {*} projectId 项目id
  34. * @param {*} cronExpression cron表达式,针对定时任务
  35. * @param {*} swaggerUrl 获取swagger的地址
  36. * @param {*} syncMode 同步模式
  37. * @param {*} uid 用户id
  38. */
  39. async addSyncJob(projectId, cronExpression, swaggerUrl, syncMode, uid) {
  40. let projectToken = await this.getProjectToken(projectId, uid);
  41. //立即执行一次
  42. this.syncInterface(projectId, swaggerUrl, syncMode, uid, projectToken);
  43. let scheduleItem = schedule.scheduleJob(cronExpression, async () => {
  44. this.syncInterface(projectId, swaggerUrl, syncMode, uid, projectToken);
  45. });
  46. //判断是否已经存在这个任务
  47. let jobItem = jobMap.get(projectId);
  48. if (jobItem) {
  49. jobItem.cancel();
  50. }
  51. jobMap.set(projectId, scheduleItem);
  52. }
  53. //同步接口
  54. async syncInterface(projectId, swaggerUrl, syncMode, uid, projectToken) {
  55. yapi.commons.log('定时器触发, syncJsonUrl:' + swaggerUrl + ",合并模式:" + syncMode);
  56. let oldPorjectData;
  57. try {
  58. oldPorjectData = await this.projectModel.get(projectId);
  59. } catch(e) {
  60. yapi.commons.log('获取项目:' + projectId + '失败');
  61. this.deleteSyncJob(projectId);
  62. //删除数据库定时任务
  63. await this.syncModel.delByProjectId(projectId);
  64. return;
  65. }
  66. //如果项目已经删除了
  67. if (!oldPorjectData) {
  68. yapi.commons.log('项目:' + projectId + '不存在');
  69. this.deleteSyncJob(projectId);
  70. //删除数据库定时任务
  71. await this.syncModel.delByProjectId(projectId);
  72. return;
  73. }
  74. let newSwaggerJsonData;
  75. try {
  76. newSwaggerJsonData = await this.getSwaggerContent(swaggerUrl)
  77. if (!newSwaggerJsonData || typeof newSwaggerJsonData !== 'object') {
  78. yapi.commons.log('数据格式出错,请检查')
  79. this.saveSyncLog(0, syncMode, "数据格式出错,请检查", uid, projectId);
  80. }
  81. newSwaggerJsonData = JSON.stringify(newSwaggerJsonData)
  82. } catch (e) {
  83. this.saveSyncLog(0, syncMode, "获取数据失败,请检查", uid, projectId);
  84. yapi.commons.log('获取数据失败' + e.message)
  85. }
  86. let oldSyncJob = await this.syncModel.getByProjectId(projectId);
  87. //更新之前判断本次swagger json数据是否跟上次的相同,相同则不更新
  88. if (newSwaggerJsonData && oldSyncJob.old_swagger_content && oldSyncJob.old_swagger_content == md5(newSwaggerJsonData)) {
  89. //记录日志
  90. this.saveSyncLog(0, syncMode, "接口无更新", uid, projectId);
  91. oldSyncJob.last_sync_time = yapi.commons.time();
  92. await this.syncModel.upById(projectId, oldSyncJob);
  93. return;
  94. }
  95. let _params = {
  96. type: 'swagger',
  97. json: newSwaggerJsonData,
  98. project_id: projectId,
  99. merge: syncMode,
  100. token: projectToken
  101. }
  102. let requestObj = {
  103. params: _params
  104. };
  105. await this.openController.importData(requestObj);
  106. //同步成功就更新同步表的数据
  107. if (requestObj.body.errcode == 0) {
  108. //修改sync_model的属性
  109. oldSyncJob.last_sync_time = yapi.commons.time();
  110. oldSyncJob.old_swagger_content = md5(newSwaggerJsonData);
  111. await this.syncModel.upById(oldSyncJob._id, oldSyncJob);
  112. }
  113. //记录日志
  114. this.saveSyncLog(requestObj.body.errcode, syncMode, requestObj.body.errmsg, uid, projectId);
  115. }
  116. getSyncJob(projectId) {
  117. return jobMap.get(projectId);
  118. }
  119. deleteSyncJob(projectId) {
  120. let jobItem = jobMap.get(projectId);
  121. if (jobItem) {
  122. jobItem.cancel();
  123. }
  124. }
  125. /**
  126. * 记录同步日志
  127. * @param {*} errcode
  128. * @param {*} syncMode
  129. * @param {*} moremsg
  130. * @param {*} uid
  131. * @param {*} projectId
  132. */
  133. saveSyncLog(errcode, syncMode, moremsg, uid, projectId) {
  134. yapi.commons.saveLog({
  135. content: '自动同步接口状态:' + (errcode == 0 ? '成功,' : '失败,') + "合并模式:" + this.getSyncModeName(syncMode) + ",更多信息:" + moremsg,
  136. type: 'project',
  137. uid: uid,
  138. username: "自动同步用户",
  139. typeid: projectId
  140. });
  141. }
  142. /**
  143. * 获取项目token,因为导入接口需要鉴权.
  144. * @param {*} project_id 项目id
  145. * @param {*} uid 用户id
  146. */
  147. async getProjectToken(project_id, uid) {
  148. try {
  149. let data = await this.tokenModel.get(project_id);
  150. let token;
  151. if (!data) {
  152. let passsalt = yapi.commons.randStr();
  153. token = sha('sha1')
  154. .update(passsalt)
  155. .digest('hex')
  156. .substr(0, 20);
  157. await this.tokenModel.save({ project_id, token });
  158. } else {
  159. token = data.token;
  160. }
  161. token = getToken(token, uid);
  162. return token;
  163. } catch (err) {
  164. return "";
  165. }
  166. }
  167. getUid(uid) {
  168. return parseInt(uid, 10);
  169. }
  170. /**
  171. * 转换合并模式的值为中文.
  172. * @param {*} syncMode 合并模式
  173. */
  174. getSyncModeName(syncMode) {
  175. if (syncMode == 'good') {
  176. return '智能合并';
  177. } else if (syncMode == 'normal') {
  178. return '普通模式';
  179. } else if (syncMode == 'merge') {
  180. return '完全覆盖';
  181. }
  182. return '';
  183. }
  184. async getSwaggerContent(swaggerUrl) {
  185. const axios = require('axios')
  186. try {
  187. let response = await axios.get(swaggerUrl);
  188. if (response.status > 400) {
  189. throw new Error(`http status "${response.status}"` + '获取数据失败,请确认 swaggerUrl 是否正确')
  190. }
  191. return response.data;
  192. } catch (e) {
  193. let response = e.response || {status: e.message || 'error'};
  194. throw new Error(`http status "${response.status}"` + '获取数据失败,请确认 swaggerUrl 是否正确')
  195. }
  196. }
  197. }
  198. module.exports = syncUtils;