<template>
  <h3>
    防伪备案系统
  </h3>
  <hr>
  <div class="fade-in">
    <div class="ops">
      快捷入口：
      <a href="/estor/import">
        导入数据
      </a>
      <a href="https://emblem-netdata.hond.cloud" target="_blank">
        主机监控
      </a>
      <a href="/estor/batches">
        批次数据管理
      </a>
      <a href="/estor/jobs">
        后台任务
      </a>
      <a href="/estor/disks">
        磁盘管理
      </a>
      <a href="/estor/backup-restore">
        备份和恢复
      </a>
    </div>
    <div>
      <CRow class="row">
        <CCol :md="3">
          <CCard class="card card-green">
            <CCardBody>
              <div class="card-title">
                总体状态
              </div>
              <div class="card-main text-success">
                正常
              </div>
            </CCardBody>
          </CCard>
        </CCol>
        <CCol :md="3">
          <CCard class="card card-green">
            <CCardBody>
              <div class="card-title">
                开机时间
              </div>
              <div class="card-main text-info">
                {{ uptime }}
              </div>
            </CCardBody>
          </CCard>
        </CCol>
        <CCol :md="3">
          <CCard class="card card-green">
            <CCardBody>
              <div class="card-title">
                批次数
              </div>
              <div class="card-main text-info">
                {{ nr_batches }}
              </div>
            </CCardBody>
          </CCard>
        </CCol>
        <CCol :md="3">
          <CCard class="card card-green">
            <CCardBody>
              <div class="card-title">
                任务数
              </div>
              <div class="card-main text-info">
                {{ nr_active_jobs }}
              </div>
            </CCardBody>
          </CCard>
        </CCol>
      </CRow>
      <CRow class="row">
        <CCol :md="7">
          <CCard>
            <CCardBody>
              <div class="card-title">
                负载
              </div>
              <LoadChart :series="cpu_mem_series" :ymax="100" />
            </CCardBody>
          </CCard>
        </CCol>
        <CCol :md="5">
          <CCard>
            <CCardBody>
              <div class="card-title">
                内存使用率
              </div>
              <PieChart :colors="colors" :used="100 - mem_avail_percent"/>
            </CCardBody>
          </CCard>
        </CCol>
      </CRow>

      <CRow class="row">
        <CCol :md="7">
          <CCard>
            <CCardBody>
              <div class="card-title">
                磁盘活动
              </div>
              <LoadChart :series="diskio_series" />
            </CCardBody>
          </CCard>
        </CCol>
        <CCol :md="5">
          <CCard>
            <CCardBody>
              <div class="card-title">
                系统盘使用
              </div>
              <PieChart :colors="colors" :used="rootfs_used_percent"/>
            </CCardBody>
          </CCard>
        </CCol>
      </CRow>

      <CRow class="row">
        <CCol :md="7">
          <CCard>
            <CCardBody>
              <div class="card-title">
                网络活动
              </div>
              <LoadChart :series="net_series" />
            </CCardBody>
          </CCard>
        </CCol>
        <CCol :md="5">
          <CCard>
            <CCardBody>
              <div class="card-title">
                数据盘使用
              </div>
              <PieChart :colors="colors" :used="data_used_percent"/>
            </CCardBody>
          </CCard>
        </CCol>
      </CRow>

      <CRow class="row">
        <CCol :md="7">
          <CCard>
            <CCardBody>
              <div class="card-title">
                设备活动
              </div>
              <LoadChart :series="hw_series" />
            </CCardBody>
          </CCard>
        </CCol>
        <CCol :md="5">
          <CCard>
            <CCardBody>
              <div class="card-title">
                GPU MEM
              </div>
              <PieChart :colors="colors" :used="gpu_mem_used"/>
            </CCardBody>
          </CCard>
        </CCol>
      </CRow>

      <CRow class="row">
        <CCol :md="3">
          <CCard class="card-blue">
            <CCardBody>
              <div class="card-title">
                CPU核数
              </div>
              <div class="card-main">
                {{ n_cpus }}
              </div>
            </CCardBody>
          </CCard>
        </CCol>
        <CCol :md="3">
          <CCard class="card-blue">
            <CCardBody>
              <div class="card-title">
                系统内存
              </div>
              <div class="card-main">
                {{ mem_gb }} GB
              </div>
            </CCardBody>
          </CCard>
        </CCol>
        <CCol :md="3">
          <CCard class="card-blue">
            <CCardBody>
              <div class="card-title">
                总进程数
              </div>
              <div class="card-main">
                {{ nr_processes }}
              </div>
            </CCardBody>
          </CCard>
        </CCol>
        <CCol :md="3">
          <CCard class="card-blue">
            <CCardBody>
              <div class="card-title">
                总线程数
              </div>
              <div class="card-main">
                {{ nr_threads }}
              </div>
            </CCardBody>
          </CCard>
        </CCol>
      </CRow>
      <CRow class="row px-3">
        数据盘
      </CRow>
      <CRow class="row">
        <CCol :md="3" v-for="x, i in [1,2,3,4,5,6,7,8]" :key="i">
          <CCard class="card-yellow my-2">
            <CCardBody>
              <div class="card-title">
                磁盘-{{ i }}
              </div>
              <div class="card-main">
                <div v-if="disks[i]" class="diskinfo row">
                  <div class="col">
                    <img src="@/assets/hd.png" alt=""/>
                  </div>
                  <div class="col diskusage">
                    已用 {{ show_size(disks[i].used) }}
                    /
                    共 {{ show_size(disks[i].total) }}
                    <CProgress>
                      <CProgressBar :value="disks[i].used * 100 / disks[i].total" />
                    </CProgress>
                  </div>
                </div>
                <div v-else>
                  未插入
                </div>
              </div>
            </CCardBody>
          </CCard>
        </CCol>
      </CRow>
    </div>
  </div>
</template>

<script>
import LoadChart from '../components/loadchart';
import PieChart from '../components/piechart';
export default {
  name: 'EstorPage',
    props: [],
    components: {
      LoadChart,
      PieChart,
    },
  data: function () {
    return {
      influx_url: 'https://influx.euphon.cloud/api/v2/query?org=Euphon',
      influx_token: 'D9NyufuaoXEJVYYgzwlIcDcqb5x1Ka2GdjlyfCWniJCpmTx2Dyz_8H8Krd5rOjBb0vW0GsFPw-XuAJWIvHVjlw==',
      influx_host: 'cn-1d950',
      uptime_seconds: 0,
      n_cpus: 0,
      mem_gb: 0,
      mem_avail_percent: 0,
      nr_processes: 0,
      nr_threads: 0,
      rootfs_used_percent: 0,
      cpu: [],
      mem: [],
      io_read_kbps: [],
      io_write_kbps: [],
      io_rx_bps: [],
      io_tx_bps: [],
      interrupts: [],
      nr_batches: 0,
      nr_active_jobs: 0,
      disks: [],
      colors: ['#e50', '#259'],
      gpu_mem_used: 0,
    };
  },
  computed: {
    data_used_percent() {
      var total = 0;
      var used = 0;
      for (var d of this.disks) {
        total += d.total;
        used += d.used;
      }
      if (!total) return 0;
      return used / total;
    },
    cpu_mem_series() {
      return [
        {
          label: 'CPU',
          color: this.colors[0],
          data: this.cpu,
        },
        {
          label: 'Memory',
          color: this.colors[1],
          data: this.mem,
        },
      ]
    },
    diskio_series() {
      return [
        {
          label: '读(KB/s)',
          color: this.colors[0],
          data: this.io_read_kbps,
        },
        {
          label: '写(KB/s)',
          color: this.colors[1],
          data: this.io_write_kbps,
        },
      ]
    },
    net_series() {
      return [
        {
          label: '发送(B/s)',
          color: this.colors[0],
          data: this.io_tx_bps,
        },
        {
          label: '接收(B/s)',
          color: this.colors[1],
          data: this.io_rx_bps,
        },
      ]
    },
    hw_series() {
      return [
        {
          label: '硬件请求',
          color: this.colors[0],
          data: this.interrupts,
        },
      ]
    },
    uptime() {
      var unit = '秒';
      var num = this.uptime_seconds;
      if (num > 86400 * 10) {
        num = num / 86400;
        unit = '天';
      } else if (num > 3600) {
        num = num / 3600;
        unit = '小时';
      } else if (num > 600) {
        num = num / 60;
        unit = '分钟';
      }
      return Math.round(num) + unit;
    },
  },
  methods: {
    async influx_query(q) {
      var r = await this.axios.post(this.influx_url, q, {
        headers: {
          Authorization: 'Token ' + this.influx_token,
          'Content-type': 'application/vnd.flux',
          'Accept': 'application/csv',
        },
      });
      var data = r.data;
      var ret = [];
      for (var x of data.split('\n')) {
        if (!x.trim().length) continue;
        ret.push(x.split(','));
      }
      return ret;
    },
    async load_single(measurement, metric) {
      var query=`
        from(bucket: "cassia")
          |> range(start: -5m)
          |> filter(fn: (r) => r["_measurement"] == "` + measurement + `")
          |> filter(fn: (r) => r["_field"] == "` + metric + `")
          |> filter(fn: (r) => r["host"] == "` + this.influx_host + `")
          |> aggregateWindow(every: 60s, fn: last, createEmpty: true)
          |> yield(name: "last")
          `;
      var r = await this.influx_query(query);
      if (r.length) {
        return r.pop()[6];
      }
      return null;
    },
    get_points(r) {
      console.log(r);
      var ret = [];
      if (r.length > 60) {
        for (var x of r.slice(-60)) {
          ret.push(x[6]);
        }
      }
      return ret;
    },
    async load_cpu() {
      var query = `
        from(bucket: "cassia")
          |> range(start: -1h)
          |> filter(fn: (r) => r["_measurement"] == "cpu")
          |> filter(fn: (r) => r["_field"] == "usage_idle")
          |> filter(fn: (r) => r["cpu"] == "cpu-total")
          |> filter(fn: (r) => r["host"] == "` + this.influx_host + `")
          |> aggregateWindow(every: 60s, fn: mean, createEmpty: true)
          |> yield(name: "mean")
          `;
      var r = await this.influx_query(query);
      this.cpu = this.get_points(r).map(x => 100 - x);
    },
    async load_mem() {
      var query = `
        from(bucket: "cassia")
          |> range(start: -1h)
          |> filter(fn: (r) => r["_measurement"] == "mem")
          |> filter(fn: (r) => r["_field"] == "used_percent")
          |> filter(fn: (r) => r["host"] == "` + this.influx_host + `")
          |> aggregateWindow(every: 60s, fn: mean, createEmpty: true)
          |> yield(name: "mean")
          `;
      var r = await this.influx_query(query);
      this.mem = this.get_points(r);
    },
    async load_disk_space() {
      var query = `
        from(bucket: "cassia")
          |> range(start: -5m)
          |> filter(fn: (r) => r["_measurement"] == "disk")
          |> filter(fn: (r) => r["_field"] == "used_percent")
          |> filter(fn: (r) => r["path"] == "/")
          |> filter(fn: (r) => r["host"] == "` + this.influx_host + `")
          |> aggregateWindow(every: 60s, fn: last, createEmpty: true)
          |> yield(name: "last")
          `;
      var r = await this.influx_query(query);
      if (r.length) {
        this.rootfs_used_percent = r.pop()[6];
      }
    },
    async load_series(measurement, metric, scale) {
      var query = `
        from(bucket: "cassia")
          |> range(start: -1h)
          |> filter(fn: (r) => r["_measurement"] == "` + measurement + `")
          |> filter(fn: (r) => r["_field"] == "` + metric + `")
          |> filter(fn: (r) => r["host"] == "` + this.influx_host + `")
          |> derivative(unit: 1s, nonNegative: true)
          |> group(columns: ["host"])
          |> aggregateWindow(every: 60s, fn: sum, createEmpty: true)
          |> yield(name: "last")
          `;
      var r = await this.influx_query(query);
      return this.get_points(r).map(x => Math.round(x * scale));
    },
    async load_gpu() {
      var measurement = 'gpu';
      var metric = 'mem';
      var query = `
        from(bucket: "emblem")
          |> range(start: -5m)
          |> filter(fn: (r) => r["_measurement"] == "` + measurement + `")
          |> filter(fn: (r) => r["_field"] == "` + metric + `")
          |> aggregateWindow(every: 60s, fn: last, createEmpty: true)
          |> yield(name: "last")
          `;
      var r = await this.influx_query(query);
      console.log("gpu loaded", r);
      if (r.length) {
        return r.pop()[6];
      }
    },
    async load_emblem_stats() {
      var r = await this.$root.estor_list(this.$root.batches_dir);
      this.nr_batches = r.map(x => x.dir).length;
      r = await this.$root.estor_call("ListJobs");
      var jobs = r.data.data;
      var total = 0;
      for (var j of jobs) {
        if (j.status == 'Running' || j.status == 'Pending') {
          total++;
        }
      }
      this.nr_active_jobs = total;
      r = await this.$root.estor_call("ListChunkStores");
      this.disks = r.data.data;
      console.log(this.disks);
    },
    refresh() {
      this.load_single("system", "uptime").then((x) => { this.uptime_seconds = x; });
      this.load_single("system", "n_cpus").then((x) => { this.n_cpus = x; });
      this.load_single("mem", "total").then((x) => { this.mem_gb = Math.round(x / 1024 / 1024 / 1024); });
      this.load_single("mem", "available_percent").then((x) => { this.mem_avail_percent = x; });
      this.load_single("processes", "total").then((x) => { this.nr_processes = x; });
      this.load_single("processes", "total_threads").then((x) => { this.nr_threads = x; });
      this.load_cpu()
      this.load_mem()
      this.load_disk_space()
      this.load_series('diskio', 'read_bytes', 0.001).then((x) => { this.io_read_kbps = x; });
      this.load_series('diskio', 'write_bytes', 0.001).then((x) => { this.io_write_kbps = x; });
      this.load_series('net', 'bytes_recv', 1).then((x) => { this.io_rx_bps = x; });
      this.load_series('net', 'bytes_sent', 1).then((x) => { this.io_tx_bps = x; });
      this.load_series('kernel', 'interrupts', 1).then((x) => { this.interrupts = x; });
      this.load_gpu().then(x => { this.gpu_mem_used = x * 100} );
      this.load_emblem_stats();
      setTimeout(this.refresh, 30000);
    },
  },
  mounted() {
    this.refresh();
  },
}
</script>

<style scoped>
.ops a {
    margin: 1rem 0.3rem;
    display: inline-block;
}
.row {
  margin-bottom: 1rem;
}

.card-title {
  font-size: 0.9rem;
  color: #888;
  padding-bottom: 0.2rem;
  border-bottom: 1px solid #ddd;
}
.card:hover .card-title {
  color: #333;
  border-bottom: 1px solid #888;
}

.card-main {
  font-size: 1.2rem;
  font-weight: bold;
}
div.card-green {
  border-bottom: 2px solid #008800;
}
div.card-yellow {
  border-bottom: 2px solid #dd0;
}
div.card-blue {
  border-bottom: 2px solid blue;
}
.card {
  box-shadow: 0px 0px 9px #ddd;
}
div.diskinfo img {
  height: 60px;
  margin: 0.5rem 0;
}
div.diskusage {
  font-size: 1rem;
}
</style>
