constructor (api, section, options) {
    this.api = api;
    this.section = section;
    this.view = '';
    this.shortcuts = {};
    if (options.dontCache) {
      this.cacheTimeout = -1;
    } else if (options.cacheTimeout !== undefined) {
      this.cacheTimeout = options.cacheTimeout;
    } else {
      this.cacheTimeout = 60 * +this.api.getConfig(section, 'cacheAgeMin', '60'); // Default an hour
    }
    this.requestStat = 0;
    this.cacheHitStat = 0;
    this.cacheMissStat = 0;
    this.cacheRefreshStat = 0;
    this.requestDroppedStat = 0;
    this.directHitStat = 0;
    this.recentAverageMS = 0;
    this.srcInProgress = {};
    this.fullQuery = !!options.fullQuery;

    if (options.typeSetting) {
      this.typeSetting();
    }

    if (options.tagsSetting) {
      this.tagsSetting();
    }

    if (options.formatSetting) {
      this.formatSetting(options.formatSetting);
    }

    let items;
    // Domain and Email wildcards to exclude from source
    ['excludeDomains', 'excludeEmails', 'excludeURLs'].forEach((type) => {
      items = api.getConfig(section, type);
      this[type] = [];
      if (!items) { return; }
      items.split(';').map(item => item.trim()).forEach((item) => {
        if (item === '') {
          return;
        }
        this[type].push(RegExp.fromWildExp(item, 'ailop'));
      });
    });

    // IP CIDRs to exclude from source
    this.excludeIPs = new iptrie.IPTrie();
    items = api.getConfig(section, 'excludeIPs', '');
    items.split(';').map(item => item.trim()).forEach((item) => {
      if (item === '') {
        return;
      }
      const parts = item.split('/');
      try {
        this.excludeIPs.add(parts[0], +parts[1] || (parts[0].includes(':') ? 128 : 32), true);
      } catch (e) {
        console.log(`${section} - ERROR - excludeIPs for '${item}'`, e);
        process.exit();
      }
    });

    items = api.getConfig(section, 'onlyIPs', undefined);
    if (items) {
      this.onlyIPs = new iptrie.IPTrie();
      items.split(';').map(item => item.trim()).forEach((item) => {
        if (item === '') {
          return;
        }
        const parts = item.split('/');
        try {
          this.onlyIPs.add(parts[0], +parts[1] || (parts[0].includes(':') ? 128 : 32), true);
        } catch (e) {
          console.log(`${section} - ERROR - onlyIPs for '${item}'`, e);
          process.exit();
        }
      });
    }

    // fields defined for source
    let fields = api.getConfig(section, 'fields');
    if (fields !== undefined) {
      fields = fields.split('\\n');
      for (let i = 0; i < fields.length; i++) {
        this.parseFieldDef(fields[i]);
      }
    }

    // views defined for source
    const view = api.getConfig(section, 'view');
    if (view !== undefined) {
      this.view = view.replace(/\\n/g, '\n');
    }

    if (this.view !== '') {
      api.addView(section, this.view);
    }
  }
Should only be created by super(api, section, options) call
@param {WISESourceAPI} api - the api when source created
@param {string} section - the section name
@param {object} options - All the options
@param {boolean} [options.dontCache=false] - do not cache this source, the source handles itself
@param {integer} [options.cacheTimeout=cacheAgeMin*60 or 60] - override the cacheAgeMin setting, -1 same as dont
@param {boolean} [options.tagsSetting=false] - load the optional tags setting
@param {boolean} [options.typeSetting=false] - load the required type setting
@param {boolean} [options.formatSetting=false] - load the format setting with default the provided value if not false
@param {boolean} [options.fullQuery=false] - for MD5/SHA, query will be query.value and query.contentType