text: import fs from 'fs';
  import Base from '~/src/commands/base';
  import { readLine } from 'lei-stream';
  import moment from 'moment';
  import Nginx from '~/src/library/nginx';
  import DATE_FORMAT from '~/src/constants/date_format';
  import Alert from '~/src/library/utils/modules/alert';
  import AlarmConfig from '~/src/configs/alarm';
  /**
   * 提供框架方法, 方便编写处理函数
   */
  
  class ParseBase extends Base {
    constructor() {
      super(); // 初始化属性(目前只能在constructor里注册属性)
      // 统一按项目进行统计
  
      this.projectMap = new Map();
      this.startAtMoment = null;
      this.endAtMoment = null;
      this.DATE_FORMAT_ARGUMENTS = DATE_FORMAT.COMMAND_ARGUMENT_BY_MINUTE;
      this.DATE_FORMAT_DISPLAY = DATE_FORMAT.COMMAND_ARGUMENT_BY_MINUTE;
    }
  
    async execute(args, options) {
      let {
        startAtYmdHi,
        endAtYmdHi
      } = args;
  
      if (this.isArgumentsLegal(args, options) === false) {
        this.warn('参数不正确, 自动退出');
        Alert.sendMessage(AlarmConfig.WATCH_UCID_LIST_DEFAULT, `${this.constructor.name}参数不正确, 自动退出`);
        return false;
      }
  
      this.startAtMoment = moment(startAtYmdHi, this.DATE_FORMAT_ARGUMENTS);
      this.endAtMoment = moment(endAtYmdHi, this.DATE_FORMAT_ARGUMENTS);
      this.log(`开始分析${this.startAtMoment.format(this.DATE_FORMAT_DISPLAY) + ':00'}~${this.endAtMoment.format(this.DATE_FORMAT_DISPLAY) + ':59'}范围内的记录`);
      let startAt = this.startAtMoment.unix();
      let endAt = this.endAtMoment.unix();
      await this.parseLog(startAt, endAt);
      this.log('全部数据处理完毕, 存入数据库中');
      let {
        totalRecordCount,
        processRecordCount,
        successSaveCount
      } = await this.save2DB();
      this.log(`${this.startAtMoment.format(this.DATE_FORMAT_DISPLAY) + ':00'}~${this.endAtMoment.format(this.DATE_FORMAT_DISPLAY) + ':59'}范围内日志录入完毕, 共记录数据${processRecordCount}/${totalRecordCount}条, 入库成功${successSaveCount}条`);
    }
    /**
     * [可覆盖]检查请求参数, 默认检查传入的时间范围是否正确, 如果有自定义需求可以在子类中进行覆盖
     * @param {*} args
     * @param {*} options
     * @return {Boolean}
     */
  
  
    isArgumentsLegal(args, options) {
      let {
        startAtYmdHi,
        endAtYmdHi
      } = args;
      let startAtMoment = moment(startAtYmdHi, DATE_FORMAT.COMMAND_ARGUMENT_BY_MINUTE);
      let endAtMoment = moment(endAtYmdHi, DATE_FORMAT.COMMAND_ARGUMENT_BY_MINUTE);
  
      if (moment.isMoment(startAtMoment) === false || startAtMoment.isValid() === false) {
        let message = `startAtYmdHi参数不正确 => ${startAtYmdHi}`;
        this.warn(message);
        Alert.sendMessage(AlarmConfig.WATCH_UCID_LIST_DEFAULT, message);
        return false;
      }
  
      if (moment.isMoment(endAtMoment) === false || endAtMoment.isValid() === false) {
        let message = `endAtYmdHi参数不正确 =>${endAtYmdHi}`;
        this.warn(message);
        Alert.sendMessage(AlarmConfig.WATCH_UCID_LIST_DEFAULT, message);
        return false;
      }
  
      if (startAtMoment.unix() > endAtMoment.unix()) {
        let message = `结束时间小于开始时间 :  ${startAtYmdHi} => ${startAtMoment.unix()} endAtYmdHi =>  ${endAtMoment.unix()}`;
        this.warn(message);
        Alert.sendMessage(AlarmConfig.WATCH_UCID_LIST_DEFAULT, message);
        return false;
      }
  
      return true;
    }
    /**
     * 解析指定时间范围内的日志记录, 并录入到数据库中
     * @param {*} startAt
     * @param {*} endAt
     * @return null
     */
  
  
    async parseLog(startAt, endAt) {
      let that = this;
  
      for (let currentAt = startAt; currentAt <= endAt; currentAt = currentAt + 60) {
        let currentAtMoment = moment.unix(currentAt);
        let absoluteLogUri = Nginx.getAbsoluteLogUriByType(currentAt, Nginx.LOG_TYPE_JSON);
        that.log(`开始处理${currentAtMoment.format(that.DATE_FORMAT_DISPLAY)}的记录, log文件地址 => ${absoluteLogUri}`);
        let logUri = Nginx.getAbsoluteLogUriByType(currentAt, Nginx.LOG_TYPE_JSON);
  
        if (fs.existsSync(logUri) === false) {
          that.log(`log文件不存在, 自动跳过 => ${absoluteLogUri}`);
          continue;
        } // 确保按文件顺序逐行读写日志
  
  
        await new Promise(function (resolve, reject) {
          let onDataReceive = async (data, next) => {
            let record = JSON.parse(data);
            that.log('parse record ', record);
  
            if (that.isLegalRecord(record)) {
              that.processRecordAndCacheInProjectMap(record);
            }
  
            next();
          };
  
          let onReadFinish = () => {
            resolve();
          };
  
          readLine(fs.createReadStream(logUri), {
            // 换行符，默认\n
            newline: '\n',
            // 是否自动读取下一行，默认false
            autoNext: false,
            // 编码器，可以为函数或字符串（内置编码器：json，base64），默认null
            encoding: null
          }).go(onDataReceive, onReadFinish);
        });
        that.log('处理完毕');
      }
    }
    /**
     * [必须覆盖]判断该条记录是不是需要解析的记录
     * 标准结构 => {"type":"product","code":10001,"detail":{"duration_ms":35544},"extra":{},"common":{"pid":"platfe_saas","uuid":"59b979cb-4e2a-4a34-aabf-5240a6794194","ssid":"c6a39184-0689-498b-b973-a5c0c9496494","ucid":1000000026017035,"timestamp":1537426981231},"msg":"","project_id":1,"time":1537426981,"ua":{"ua":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/537.36 (@33cd7097eede00b9c4ce59f5cf7d0e7f1eee86d8) Safari/537.36 nw(0.30.5) dtsaas(2.0.11)","browser":{"name":"Chrome","version":"537.36","major":"537"},"engine":{"name":"WebKit","version":"537.36"},"os":{"name":"Windows","version":"7"},"device":{},"cpu":{}},"ip":"60.169.167.181","country":"中国","province":"北京","city":"北京"}
     * @param {Object} record
     * @return {Boolean}
     */
  
  
    isLegalRecord(record) {
      this.mustBeOverride(); // let recordType = get(record, ['type'], '')
      // let code = get(record, ['code'], '')
      // let projectId = get(record, ['project_id'], '')
      // let durationMs = get(record, ['detail', 'duration_ms'], '')
      // code = parseInt(code)
      // durationMs = parseInt(durationMs)
      // projectId = parseInt(projectId)
      // if (recordType !== LegalRecordType) {
      //   return false
      // }
      // if (isNumber(code) === false) {
      //   return false
      // }
      // if (code !== LegalRecordCode) {
      //   return false
      // }
      // if (isNumber(projectId) === false) {
      //   return false
      // }
      // if (projectId < 0) {
      //   return false
      // }
      // if (isNumber(durationMs) === false) {
      //   return false
      // }
      // if (durationMs > MaxAllowRecordDuringMs) {
      //   return false
      // }
      // if (durationMs < MinAllowRecordDuringMs) {
      //   return false
      // }
  
      return true;
    }
    /**
     * [必须覆盖]处理记录, 并将结果缓存在this.ProjectMap中
     * {"type":"product","code":10001,"detail":{"duration_ms":30807},"extra":{},"common":{"pid":"platfe_saas","uuid":"d0511ce2-2482-4f7b-8f11-09ed75004963","ssid":"0c11d4b5-b970-419c-b1ac-f1b7922398fc","ucid":null,"timestamp":1537365073569},"msg":""}
     * @param {Object} record
     */
  
  
    async processRecordAndCacheInProjectMap(record) {
      this.mustBeOverride(); // let projectId = get(record, ['project_id'], 0)
      // let durationMs = get(record, ['detail', 'duration_ms'], 0)
      // let country = get(record, ['country'], '')
      // let province = get(record, ['province'], '')
      // let city = get(record, ['city'], '')
      // let recordAt = get(record, ['time'], 0)
      // let countAtTime = moment.unix(recordAt).format(COUNT_BY_HOUR_DATE_FORMAT)
      // let distributionPath = [country, province, city]
      // let countAtMap = new Map()
      // let distribution = {}
      // if (this.projectMap.has(projectId)) {
      //   countAtMap = this.projectMap.get(projectId)
      //   if (countAtMap.has(countAtTime)) {
      //     distribution = countAtMap.get(countAtTime)
      //     if (has(distribution, distributionPath)) {
      //       let oldDurationMs = get(distribution, distribution, 0)
      //       durationMs = durationMs + oldDurationMs
      //     }
      //   }
      // }
      // set(distribution, distributionPath, durationMs)
      // countAtMap.set(countAtTime, distribution)
      // this.projectMap.set(projectId, countAtMap)
  
      return true;
    }
    /**
     * [必须覆盖]将数据同步到数据库中
     */
  
  
    async save2DB() {
      this.mustBeOverride();
      let processRecordCount = 0;
      let successSaveCount = 0;
      let totalRecordCount = this.getRecordCountInProjectMap(); // 处理的时候调一下这个方法, 专业打印处理进度
  
      this.reportProcess(processRecordCount, successSaveCount, totalRecordCount); // for (let [projectId, countAtMap] of projectMap) {
      //   for (let [countAtTime, distribution] of countAtMap) {
      //     let recordList = MCityDistribution.getFlattenCityRecordListInDistribution(distribution)
      //     let totalStayMs = 0
      //     for (let record of recordList) {
      //       totalStayMs = totalStayMs + record
      //     }
      //     let totalUv = await MUniqueView.getTotalUv(projectId, countAtTime, COUNT_TYPE_HOUR)
      //     let isSuccess = await replaceAndAutoIncreaseTotalStayMsInUvRecord(projectId, totalStayMs, totalUv, countAtTime, COUNT_TYPE_HOUR, distribution)
      //     processRecordCount = processRecordCount + 1
      //     if (isSuccess) {
      //       successSaveCount = successSaveCount + 1
      //     }
      //     if (processRecordCount % 100 === 0) {
      //       this.log(`当前已处理${processRecordCount}/${totalRecordCount}条记录, 其中, 入库成功${successSaveCount}条`)
      //     }
      //   }
      // }
  
      return {
        totalRecordCount,
        processRecordCount,
        successSaveCount
      };
    }
    /**
     * 汇报进度
     * @param {*} processRecordCount
     * @param {*} successSaveCount
     * @param {*} totalRecordCount
     */
  
  
    reportProcess(processRecordCount, successSaveCount, totalRecordCount, tableName = '') {
      let insertTable = '';
  
      if (tableName) {
        insertTable = `, 入库${tableName}`;
      }
  
      if (processRecordCount % 100 === 0) {
        this.log(`当前已处理${processRecordCount}/${totalRecordCount}条记录${insertTable}, 已成功${successSaveCount}条`);
      }
    }
    /**
     * [必须覆盖]统计 projectUvMap 中的记录总数
     */
  
  
    getRecordCountInProjectMap() {
      this.mustBeOverride();
      let totalCount = 0; // for (let [projectId, countAtMap] of projectMap) {
      //   for (let [countAtTime, distribution] of countAtMap) {
      //     totalCount = totalCount + 1
      //   }
      // }
  
      return totalCount;
    }
  
    mustBeOverride() {
      this.warn('注意, 这里有个方法没有覆盖');
      this.warn('当场退出←_←');
      process.exit(0);
    }
  
  }
  
  export default ParseBase;
  //# sourceMappingURL=base.js.map