/*    Copyright 2021 Firewalla INC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';

const log = require('../net2/logger.js')(__filename)

const Sensor = require('./Sensor.js').Sensor

const extensionManager = require('./ExtensionManager.js')

const Promise = require('bluebird');

const fireRouter = require('../net2/FireRouter.js')

const delay = require('../util/util.js').delay;

const fs = require('fs');
Promise.promisifyAll(fs);


class LiveStatsPlugin extends Sensor {

  apiRun() {
    extensionManager.onGet("liveStats", async (msg, data) => {
      const intfs = fireRouter.getLogicIntfNames();
      const intfStats = [];
      const promises = intfs.map( async (intf) => {
        const rate = await this.getRate(intf);
        intfStats.push(rate);
      });
      promises.push(delay(1000)); // at least wait for 1 sec
      await Promise.all(promises);
      return {intfStats};
    });
  }

  async getIntfStats(intf) {
    const rx = await fs.readFileAsync(`/sys/class/net/${intf}/statistics/rx_bytes`, 'utf8');
    const tx = await fs.readFileAsync(`/sys/class/net/${intf}/statistics/tx_bytes`, 'utf8');
    return {rx, tx};
  }

  async getRate(intf) {
    const s1 = await this.getIntfStats(intf);
    await delay(1000);
    const s2 = await this.getIntfStats(intf);
    return {
      name: intf,
      rx: s2.rx > s1.rx ? s2.rx - s1.rx : 0,
      tx: s2.tx > s1.tx ? s2.tx - s1.tx : 0
    };
  }  
}

module.exports = LiveStatsPlugin;

@@ -1034,16 +1034,123 @@
 l(fs);%0A%0A
+const exec = require('child-process-promise').exec;%0A%0Aconst sysManager = require('../net2/SysManager.js');%0A%0A
 %0Aclass L
@@ -1184,16 +1184,22 @@
 or %7B%0A%0A  
+async 
 apiRun()
@@ -1197,24 +1197,238 @@
  apiRun() %7B%0A
+    this.activeConnCount = await this.getActiveConnections();%0A%0A    this.timer = setInterval(async () =%3E %7B%0A      this.activeConnCount = await this.getActiveConnections();      %0A    %7D, 300 * 1000); // every 5 mins;%0A%0A
     extensio
@@ -1816,16 +1816,50 @@
 ntfStats
+, activeConn: this.activeConnCount
 %7D;%0A    %7D
@@ -2376,18 +2376,1149 @@
   %7D;%0A  %7D
-  
+%0A%0A  buildActiveConnGrepString() %7B%0A    const wanIPs = sysManager.myWanIps();%0A    let str = %22grep -v TIME_WAIT %7C fgrep -v '127.0.0.1' %22;%0A    for(const ip of wanIPs) %7B%0A      str += %60%7C egrep -v '=$%7Bip%7D.*=$%7Bip%7D'%60;%0A    %7D%0A    return str;%0A  %7D%0A%0A  async getActiveConnections() %7B%0A    // TBD, to be improved on the data accuracy and data parsing%0A    try %7B%0A      const ipv4Cmd = %60sudo conntrack -o extended -L %7C $%7Bthis.buildActiveConnGrepString()%7D %7C wc -l%60;%0A      log.debug(ipv4Cmd);%0A      const ipv4Count = await exec(ipv4Cmd);%0A      try %7B%0A        await exec(%22sudo modinfo nf_conntrack_ipv6%22); // check if ipv6 kernel module is loaded, if not loaded, do not use the ipv6 data, which is not correct%0A        const ipv6Cmd = %22sudo conntrack -L -f ipv6 2%3E/dev/null %7C fgrep -v =::1 %7C wc -l%22;%0A        const ipv6Count = await exec(ipv6Cmd);%0A        return Number(ipv4Count.stdout) + Number(ipv6Count.stdout);%0A      %7D catch(err) %7B%0A        log.error(%22IPv6 conntrack kernel module not available%22);%0A        return Number(ipv4Count.stdout);%0A      %7D%0A    %7D catch(err) %7B%0A      log.error(%22Failed to get active connections, err:%22, err);%0A      return 0;%0A    %7D%0A  %7D
 %0A%7D%0A%0Amodu

add active conn tracking