lrf 1 年之前
当前提交
60258315e0
共有 20 个文件被更改,包括 603 次插入0 次删除
  1. 29 0
      .autod.conf.js
  2. 1 0
      .eslintignore
  3. 3 0
      .eslintrc
  4. 14 0
      .gitignore
  5. 12 0
      .travis.yml
  6. 11 0
      README.md
  7. 67 0
      app/controller/home.js
  8. 17 0
      app/router.js
  9. 23 0
      app/service/home.js
  10. 108 0
      app/service/util/http-util.js
  11. 72 0
      app/service/util/rabbitMq.js
  12. 75 0
      app/service/util/util.js
  13. 14 0
      appveyor.yml
  14. 43 0
      config/config.default.js
  15. 9 0
      config/plugin.js
  16. 17 0
      ecosystem.config.js
  17. 5 0
      jsconfig.json
  18. 54 0
      package.json
  19. 9 0
      server.js
  20. 20 0
      test/app/controller/home.test.js

+ 29 - 0
.autod.conf.js

@@ -0,0 +1,29 @@
+'use strict';
+
+module.exports = {
+  write: true,
+  prefix: '^',
+  plugin: 'autod-egg',
+  test: [
+    'test',
+    'benchmark',
+  ],
+  dep: [
+    'egg',
+    'egg-scripts',
+  ],
+  devdep: [
+    'egg-ci',
+    'egg-bin',
+    'egg-mock',
+    'autod',
+    'autod-egg',
+    'eslint',
+    'eslint-config-egg',
+  ],
+  exclude: [
+    './test/fixtures',
+    './dist',
+  ],
+};
+

+ 1 - 0
.eslintignore

@@ -0,0 +1 @@
+coverage

+ 3 - 0
.eslintrc

@@ -0,0 +1,3 @@
+{
+  "extends": "eslint-config-egg"
+}

+ 14 - 0
.gitignore

@@ -0,0 +1,14 @@
+logs/
+npm-debug.log
+yarn-error.log
+node_modules/
+package-lock.json
+yarn.lock
+coverage/
+.idea/
+run/
+.DS_Store
+*.sw*
+*.un~
+typings/
+.nyc_output/

+ 12 - 0
.travis.yml

@@ -0,0 +1,12 @@
+
+language: node_js
+node_js:
+  - '10'
+before_install:
+  - npm i npminstall -g
+install:
+  - npminstall
+script:
+  - npm run ci
+after_script:
+  - npminstall codecov && codecov

+ 11 - 0
README.md

@@ -0,0 +1,11 @@
+# server-baoan
+
+保安服务端
+
+# 看其他的.md文件比这个有用多了
+## 本地运行: npm run dev
+## 服务器使用 pm2 管理,常用指令:
+ 1. pm2 start :在项目的根目录,就是能看到 `ecosystem.config.js` 和 `server.js` 的地方用
+ 2. pm2 stop xxx:停止pm2管理的某个项目 xxx可以写项目名(`ecosystem.config.js文件中的app就是这个项目在pm2的任务名称`),可以写自动排的编号,在列表里都能看到.不限制使用的地方
+ 3. pm2 list :查看pm2运行中的项目列表
+ 4. 更多指令自行去官网找

+ 67 - 0
app/controller/home.js

@@ -0,0 +1,67 @@
+'use strict';
+const Controller = require('egg').Controller;
+const { CrudController } = require('naf-framework-mongoose-free/lib/controller');
+const fs = require('fs');
+const assert = require('assert');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const _ = require('lodash');
+
+class HomeController extends Controller {
+  constructor(ctx) {
+    super(ctx);
+    this.service = this.ctx.service.home;
+    this.http = this.ctx.service.util.httpUtil;
+  }
+  async index() {
+    const { ctx } = this;
+    ctx.body = 'hi, egg';
+  }
+  async request() {
+    const res = await this.service.request();
+    this.ctx.body = res;
+  }
+
+  async upload() {
+    const { appid } = this.ctx.params;
+    assert(appid);
+    const file = this.ctx.request.files[0];
+    const uarr = this.ctx.request.url.split('/');
+    uarr.pop();
+    console.log(uarr);
+    const uri = `${uarr.join('/')}/`;
+    if (!file) throw new BusinessError(ErrorCode.FILE_FAULT, '未获取到文件');
+    const { filepath } = file;
+    const { filename } = file;
+    const arr = filename.split('.');
+    const name = new Date().getTime();
+    const extension = `${_.last(arr)}`;
+    const object = { uri, name, extension };
+    const picBuffer = fs.readFileSync(filepath);
+    const code = this.turnImageToBase64({ extension, buffer: picBuffer });
+    if (code) object.code = code;
+    // console.log(object);
+    const reqUrl = '/files/server/upload';
+    const res = await this.http.$post(reqUrl, object);
+    console.log(res);
+    const resData = _.get(res, 'data');
+    if (resData) this.ctx.body = { errcode: 0, errmsg: 'ok', ...resData };
+    else this.ctx.body = { errcode: -1, errmsg: '上传失败' };
+  }
+
+  /**
+   * 转换图片为base64
+   * @param {Object} object excel获取的图片object
+   * @property extension  后缀,文件类型
+   * @property buffer 图片内容,不含头部信息的,
+   */
+  turnImageToBase64(object = {}) {
+    const { extension, buffer } = object;
+    if (extension && buffer) {
+      const suffix = object.extension;
+      const ib = object.buffer.toString('base64');
+      const base64 = `data:image/${suffix};base64,${ib}`;
+      return base64;
+    }
+  }
+}
+module.exports = CrudController(HomeController, {});

+ 17 - 0
app/router.js

@@ -0,0 +1,17 @@
+'use strict';
+
+/**
+ * @param {Egg.Application} app - egg application
+ */
+module.exports = app => {
+  const { router, controller } = app;
+  // 上传
+  router.post('/:appid/upload', controller.home.upload);
+  router.post('/:appid/:catalog/upload', controller.home.upload);
+  router.post('/:appid/:catalog/:item/upload', controller.home.upload);
+  
+  router.get(/^\/api*/, controller.home.request);
+  router.post(/^\/api*/, controller.home.request);
+  router.delete(/^\/api*/, controller.home.request);
+
+};

+ 23 - 0
app/service/home.js

@@ -0,0 +1,23 @@
+'use strict';
+const { CrudService } = require('naf-framework-mongoose-free/lib/service');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const _ = require('lodash');
+const assert = require('assert');
+
+//
+class HomeService extends CrudService {
+  constructor(ctx) {
+    super(ctx, 'home');
+    this.http = this.ctx.service.util.httpUtil;
+  }
+  async request() {
+    const url = this.ctx.request.url;
+    const body = this.ctx.request.body;
+    const method = _.lowerCase(this.ctx.request.method);
+    // query的参数直接在url中,所以不管走哪个方法,第二个参数都是body就可以了
+    const res = await this.http[`$${method}`](url, body);
+    return res;
+  }
+}
+
+module.exports = HomeService;

+ 108 - 0
app/service/util/http-util.js

@@ -0,0 +1,108 @@
+'use strict';
+const { AxiosService } = require('naf-framework-mongoose-free/lib/service');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const { isNullOrUndefined } = require('naf-core').Util;
+const _ = require('lodash');
+
+//
+class HttpUtilService extends AxiosService {
+  constructor(ctx) {
+    super(ctx, {}, {});
+    this.serverPort = this.app.config.serverPort;
+    this.serverIp = this.app.config.serverIp;
+  }
+
+
+  // 替换uri中的参数变量
+  merge(uri, query = {}) {
+    const keys = Object.keys(query);
+    const arr = [];
+    for (const k of keys) {
+      arr.push(`${k}=${query[k]}`);
+    }
+    if (arr.length > 0) {
+      uri = `${uri}?${arr.join('&')}`;
+    }
+    return uri;
+  }
+
+  /**
+   * curl-get请求
+   * @param {String} uri 接口地址
+   * @param {Object} query 地址栏参数
+   * @param {Object} options 额外参数
+   */
+  async $get(uri, query, options) {
+    return this.toRequest(uri, null, query, options);
+  }
+
+  /**
+   * curl-post请求
+   * @param {String} uri 接口地址
+   * @param {Object} data post的body
+   * @param {Object} query 地址栏参数
+   * @param {Object} options 额外参数
+   */
+  async $post(uri, data = {}, query, options) {
+    return this.toRequest(uri, data, query, options);
+  }
+
+  /**
+   * curl-post请求
+   * @param {String} uri 接口地址
+   * @param {Object} data post的body
+   * @param {Object} query 地址栏参数
+   * @param {Object} options 额外参数
+   */
+  async $delete(uri, data = {}, query, options) {
+    options = { ...options, method: 'delete' };
+    return this.toRequest(uri, data, query, options);
+  }
+
+  async toRequest(uri, data, query, options) {
+    query = _.pickBy(
+      query,
+      val => val !== '' && val !== 'undefined' && val !== 'null'
+    );
+    if (!uri) console.error('uri不能为空');
+    if (_.isObject(query) && _.isObject(options)) {
+      const params = query.params ? query.params : query;
+      options = { ...options, params };
+    } else if (_.isObject(query) && !query.params) {
+      options = { params: query };
+    } else if (_.isObject(query) && query.params) {
+      options = query;
+    }
+    // 是否多租户模式,需要改变headers
+    const headers = { 'content-type': 'application/json' };
+    const authorization = _.get(this.ctx.request.header, 'authorization');
+    if (authorization) headers.authorization = authorization;
+    const url = this.merge(`http://${this.serverIp}:${this.serverPort}${uri}`, options.params);
+    console.log(url);
+    console.log(data);
+    const res = await this.ctx.curl(url, {
+      method: isNullOrUndefined(data) ? 'get' : 'post',
+      url,
+      data,
+      dataType: 'json',
+      headers,
+      ...options,
+      timeout: 6000,
+    });
+    console.log(res.data);
+    return res.data;
+    // if (res.status === 200) {
+    //   res = res.data || {};
+    //   const { code, message } = res;
+    //   if (code) {
+    //     console.warn(`[${uri}] fail: ${code}-${message} `);
+    //     return { code, message };
+    //   }
+    //   return res.data;
+    // }
+    // const { status } = res;
+    // console.warn(`[${uri}] fail: ${status}-${res.data.message} `);
+  }
+}
+
+module.exports = HttpUtilService;

+ 72 - 0
app/service/util/rabbitMq.js

@@ -0,0 +1,72 @@
+'use strict';
+
+const Service = require('egg').Service;
+const _ = require('lodash');
+
+class RabbitmqService extends Service {
+
+  constructor(ctx) {
+    super(ctx);
+    this.exType = 'topic';
+    this.durable = true;
+  }
+
+  // 接收消息
+  async receiveQueueMsg(ex) {
+    this.ctx.logger.info('调用mq的' + ex);
+    const self = this;
+    const { mq } = self.ctx;
+    if (mq) {
+      const ch = await mq.conn.createChannel();
+      await ch.assertExchange(ex, 'topic', { durable: true });
+      const q = await ch.assertQueue('', { exclusive: true });
+      await ch.bindQueue(q.queue, ex, '*');
+      await ch.consume(q.queue, msg => this.logMessage(msg, this), { noAck: true });
+    } else {
+      this.ctx.logger.error('!!!!!!没有配置MQ插件!!!!!!');
+    }
+  }
+
+  async logMessage(msg) {
+    const result = msg.content.toString();
+    const headers = msg.properties.headers;
+  }
+
+  // mission队列处理
+  async mission() {
+    const { mq } = this.ctx;
+    if (mq) {
+      const ch = await mq.conn.createChannel();
+      const queue = 'mission/baoan';
+      try {
+        // 创建队列:在没有队列的情况,直接获取会导致程序无法启动
+        await ch.assertQueue(queue, { durable: false });
+        await ch.consume(queue, msg => this.dealMission(msg), { noAck: true });
+      } catch (error) {
+        this.ctx.logger.error('未找到订阅的队列');
+      }
+    } else {
+      this.ctx.logger.error('!!!!!!没有配置MQ插件!!!!!!');
+    }
+  }
+  // 执行任务
+  async dealMission(bdata) {
+    if (!bdata) this.ctx.logger.error('mission队列中信息不存在');
+    let data = bdata.content.toString();
+    try {
+      data = JSON.parse(data);
+    } catch (error) {
+      this.ctx.logger.error('数据不是object');
+    }
+    const { service, method, project, ...others } = data;
+    const arr = service.split('.');
+    let s = this.ctx.service;
+    for (const key of arr) {
+      s = s[key];
+    }
+    s[method](others);
+
+  }
+}
+
+module.exports = RabbitmqService;

+ 75 - 0
app/service/util/util.js

@@ -0,0 +1,75 @@
+'use strict';
+const _ = require('lodash');
+const moment = require('moment');
+const { CrudService } = require('naf-framework-mongoose-free/lib/service');
+const { ObjectId } = require('mongoose').Types;
+const fs = require('fs');
+class UtilService extends CrudService {
+  constructor(ctx) {
+    super(ctx);
+    this.mq = this.ctx.mq;
+  }
+  async utilMethod(query, body) {
+  }
+
+  async expertExport() {
+  }
+
+
+  dealQuery(query) {
+    return this.turnFilter(this.turnDateRangeQuery(query));
+  }
+
+  /**
+   * 将查询条件中模糊查询的标识转换成对应object
+   * @param {Object} filter 查询条件
+   */
+  turnFilter(filter) {
+    const str = /^%\S*%$/;
+    const keys = Object.keys(filter);
+    for (const key of keys) {
+      const res = key.match(str);
+      if (res) {
+        const newKey = key.slice(1, key.length - 1);
+        filter[newKey] = new RegExp(filter[key]);
+        delete filter[key];
+      }
+    }
+    return filter;
+  }
+  /**
+   * 将时间转换成对应查询Object
+   * @param {Object} filter 查询条件
+   */
+  turnDateRangeQuery(filter) {
+    const keys = Object.keys(filter);
+    for (const k of keys) {
+      if (k.includes('@')) {
+        const karr = k.split('@');
+        if (karr.length === 2) {
+          const type = karr[1];
+          if (type === 'start') {
+            if (filter[k] && filter[k] !== '') {
+              filter[karr[0]] = {
+                ..._.get(filter, karr[0], {}),
+                $gte: filter[k],
+              };
+            }
+
+          } else {
+            if (filter[k] && filter[k] !== '') {
+              filter[karr[0]] = {
+                ..._.get(filter, karr[0], {}),
+                $lte: filter[k],
+              };
+            }
+          }
+          delete filter[k];
+        }
+      }
+    }
+    return filter;
+  }
+
+}
+module.exports = UtilService;

+ 14 - 0
appveyor.yml

@@ -0,0 +1,14 @@
+environment:
+  matrix:
+    - nodejs_version: '10'
+
+install:
+  - ps: Install-Product node $env:nodejs_version
+  - npm i npminstall && node_modules\.bin\npminstall
+
+test_script:
+  - node --version
+  - npm --version
+  - npm run test
+
+build: off

+ 43 - 0
config/config.default.js

@@ -0,0 +1,43 @@
+/* eslint valid-jsdoc: "off" */
+
+'use strict';
+
+/**
+ * @param {Egg.EggAppInfo} appInfo app info
+ */
+
+module.exports = appInfo => {
+  /**
+   * built-in config
+   * @type {Egg.EggAppConfig}
+   **/
+  const config = (exports = {});
+
+  // use for cookie sign key, should change to your own and keep security
+  config.keys = appInfo.name + '_1629889590707_2425';
+
+  // add your middleware config here
+  config.middleware = [];
+
+  // add your user config here
+  const userConfig = {
+    // myAppName: 'egg',
+  };
+  config.cluster = {
+    listen: {
+      port: 6199,
+    },
+  };
+  config.multipart = {
+    mode: 'file',
+  };
+  config.serverPort = '8090';
+  config.serverIp = 'baoan.fwedzgc.com'; // 106.12.161.200;222.169.249.162
+  // config.serverPort = '8001';
+  // config.serverIp = 'localhost'; // 106.12.161.200
+
+  return {
+    ...config,
+    ...userConfig,
+  };
+};

+ 9 - 0
config/plugin.js

@@ -0,0 +1,9 @@
+'use strict';
+
+/** @type Egg.EggPlugin */
+module.exports = {
+  // had enabled by egg
+  // static: {
+  //   enable: true,
+  // }
+};

+ 17 - 0
ecosystem.config.js

@@ -0,0 +1,17 @@
+'use strict';
+
+const app = 'baoan-redirect';
+module.exports = {
+  apps: [{
+    name: app, // 应用名称
+    script: './server.js', // 实际启动脚本
+    out: `./logs/${app}.log`,
+    error: `./logs/${app}.err`,
+    watch: [ // 监控变化的目录,一旦变化,自动重启
+      'app', 'config',
+    ],
+    env: {
+      NODE_ENV: 'production', // 环境参数,当前指定为生产环境
+    },
+  }],
+};

+ 5 - 0
jsconfig.json

@@ -0,0 +1,5 @@
+{
+  "include": [
+    "**/*"
+  ]
+}

+ 54 - 0
package.json

@@ -0,0 +1,54 @@
+{
+  "name": "baoan-redirect",
+  "version": "1.0.0",
+  "description": "保安服务端https转发",
+  "private": true,
+  "egg": {
+    "framework": "naf-framework-mongoose-free"
+  },
+  "dependencies": {
+    "co-wechat-api": "^3.11.0",
+    "egg": "^2.15.1",
+    "egg-naf-amqp": "0.0.13",
+    "egg-redis": "^2.4.0",
+    "egg-scripts": "^2.11.0",
+    "exceljs": "^4.2.0",
+    "lodash": "^4.17.15",
+    "moment": "^2.24.0",
+    "naf-framework-mongoose-free": "0.0.2"
+  },
+  "devDependencies": {
+    "autod": "^3.0.1",
+    "autod-egg": "^1.1.0",
+    "egg-bin": "^4.11.0",
+    "egg-ci": "^1.11.0",
+    "egg-mock": "^3.21.0",
+    "eslint": "^5.13.0",
+    "eslint-config-egg": "^7.1.0",
+    "jsonwebtoken": "^8.5.1"
+  },
+  "engines": {
+    "node": ">=10.0.0"
+  },
+  "scripts": {
+    "start": "egg-scripts start  --title=egg-server-server-baoan",
+    "stop": "egg-scripts stop --title=egg-server-server-baoan",
+    "dev": "egg-bin dev",
+    "debug": "egg-bin debug",
+    "test": "npm run lint -- --fix && npm run test-local",
+    "test-local": "egg-bin test",
+    "cov": "egg-bin cov",
+    "lint": "eslint .",
+    "ci": "npm run lint && npm run cov",
+    "autod": "autod"
+  },
+  "ci": {
+    "version": "10"
+  },
+  "repository": {
+    "type": "git",
+    "url": ""
+  },
+  "author": "lrf",
+  "license": "MIT"
+}

+ 9 - 0
server.js

@@ -0,0 +1,9 @@
+
+// eslint-disable-next-line strict
+const egg = require('egg');
+
+const workers = Number(process.argv[2] || require('os').cpus().length);
+egg.startCluster({
+  workers,
+  baseDir: __dirname,
+});

+ 20 - 0
test/app/controller/home.test.js

@@ -0,0 +1,20 @@
+'use strict';
+
+const { app, assert } = require('egg-mock/bootstrap');
+
+describe('test/app/controller/home.test.js', () => {
+  it('should assert', () => {
+    const pkg = require('../../../package.json');
+    assert(app.config.keys.startsWith(pkg.name));
+
+    // const ctx = app.mockContext({});
+    // yield ctx.service.xx();
+  });
+
+  it('should GET /', () => {
+    return app.httpRequest()
+      .get('/')
+      .expect('hi, egg')
+      .expect(200);
+  });
+});