statistics.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. "use strict"
  2. define(["lib/helper"], function (Helper) {
  3. function streamElement(type, stream) {
  4. var el = document.createElement(type)
  5. el.destroy = stream.onValue(update)
  6. function update(d) {
  7. el.textContent = d
  8. }
  9. return el
  10. }
  11. function streamNode(stream) {
  12. var el = document.createTextNode("")
  13. el.destroy = stream.onValue(update)
  14. function update(d) {
  15. el.textContent = d
  16. }
  17. return el
  18. }
  19. function mkRow(table, label, stream, sorted) {
  20. var i = -1
  21. if (sorted) {
  22. for (i = 0; i < table.rows.length; i++) {
  23. if (label < table.rows[i].firstChild.textContent)
  24. break
  25. }
  26. }
  27. var tr = table.insertRow(i)
  28. var th = document.createElement("th")
  29. var td = streamElement("td", stream)
  30. th.textContent = label
  31. tr.appendChild(th)
  32. tr.appendChild(td)
  33. tr.destroy = function () {
  34. td.destroy()
  35. table.tBodies[0].removeChild(tr)
  36. }
  37. return tr
  38. }
  39. function mkTrafficRow(table, children, label, stream, selector) {
  40. var tr = table.insertRow()
  41. var th = document.createElement("th")
  42. th.textContent = label
  43. tr.appendChild(th)
  44. var td = tr.insertCell()
  45. var traffic = stream.slidingWindow(2, 2)
  46. var pkts = streamNode(traffic.map(deltaUptime(selector + ".packets")).map(prettyPackets))
  47. var bw = streamNode(traffic.map(deltaUptime(selector + ".bytes")).map(prettyBits))
  48. var bytes = streamNode(stream.map(selector).map(".bytes").map(prettyBytes))
  49. td.appendChild(pkts)
  50. td.appendChild(document.createElement("br"))
  51. td.appendChild(bw)
  52. td.appendChild(document.createElement("br"))
  53. td.appendChild(bytes)
  54. children.push(pkts)
  55. children.push(bw)
  56. children.push(bytes)
  57. }
  58. function mkMeshVPN(el, stream) {
  59. var children = {}
  60. var init = false
  61. var h = document.createElement("h3")
  62. h.textContent = "Mesh-VPN"
  63. var table = document.createElement("table")
  64. var unsubscribe = stream.onValue( function (d) {
  65. function addPeer(peer, path) {
  66. return { peer: peer, path: path }
  67. }
  68. function addPeers(d, path) {
  69. if (!("peers" in d))
  70. return []
  71. var peers = []
  72. for (var peer in d.peers)
  73. peers.push(addPeer(peer, path + ".peers." + peer))
  74. return peers
  75. }
  76. function addGroup(d, path) {
  77. var peers = []
  78. peers = peers.concat(addPeers(d, path))
  79. if ("groups" in d)
  80. for (var group in d.groups)
  81. peers = peers.concat(addGroup(d.groups[group], path + ".groups." + group))
  82. return peers
  83. }
  84. if (d === undefined)
  85. clear()
  86. else {
  87. if (!init) {
  88. init = true
  89. el.appendChild(h)
  90. el.appendChild(table)
  91. }
  92. var peers = addGroup(d, "")
  93. var paths = new Set(peers.map(function (d) { return d.path } ))
  94. for (var path in children)
  95. if (!paths.has(path)) {
  96. children[path].destroy()
  97. delete children[path]
  98. }
  99. peers.forEach( function (peer) {
  100. if (!(peer.path in children))
  101. children[peer.path] = mkRow(table, peer.peer,
  102. stream.startWith(d)
  103. .map(peer.path)
  104. .filter(function (d) { return d !== undefined })
  105. .map(prettyPeer), true)
  106. })
  107. }
  108. })
  109. function clear() {
  110. if (init) {
  111. init = false
  112. el.removeChild(h)
  113. el.removeChild(table)
  114. }
  115. for (var peer in children)
  116. children[peer].destroy()
  117. children = {}
  118. }
  119. function destroy() {
  120. unsubscribe()
  121. clear()
  122. }
  123. return { destroy: destroy }
  124. }
  125. function deltaUptime(selector) {
  126. return function (d) {
  127. var deltaTime = d[1].uptime - d[0].uptime
  128. var d0 = Helper.dictGet(d[0], selector.split(".").splice(1))
  129. var d1 = Helper.dictGet(d[1], selector.split(".").splice(1))
  130. return (d1 - d0) / deltaTime
  131. }
  132. }
  133. function prettyPeer(d) {
  134. if (d === null)
  135. return "nicht verbunden"
  136. else
  137. return "verbunden (" + prettyUptime(d.established) + ")"
  138. }
  139. function prettyPackets(d) {
  140. var v = Helper.formatNumberFixed(d, 0)
  141. return v + " Pakete/s"
  142. }
  143. function prettyPrefix(prefixes, step, d) {
  144. var prefix = 0
  145. while (d > step && prefix < prefixes.length - 1) {
  146. d /= step
  147. prefix++
  148. }
  149. d = Helper.formatNumber(d, 3)
  150. return d + " " + prefixes[prefix]
  151. }
  152. function prettySize(d) {
  153. return prettyPrefix([ "", "k", "M", "G", "T" ], 1024, d)
  154. }
  155. function prettyBits(d) {
  156. return prettySize(d * 8) + "bps"
  157. }
  158. function prettyBytes(d) {
  159. return prettySize(d) + "B"
  160. }
  161. function prettyUptime(seconds) {
  162. var minutes = Math.round(seconds / 60)
  163. var days = Math.floor(minutes / 1440)
  164. var hours = Math.floor((minutes % 1440) / 60)
  165. minutes = Math.floor(minutes % 60)
  166. var out = ""
  167. if (days === 1)
  168. out += "1 Tag, "
  169. else if (days > 1)
  170. out += days + " Tage, "
  171. out += hours + ":"
  172. if (minutes < 10)
  173. out += "0"
  174. out += minutes
  175. return out
  176. }
  177. function prettyNVRAM(usage) {
  178. return Helper.formatNumber(usage * 100, 3) + "% belegt"
  179. }
  180. function prettyLoad(load) {
  181. return Helper.formatNumberFixed(load, 2)
  182. }
  183. function prettyRAM(memory) {
  184. var usage = 1 - (memory.free + memory.buffers + memory.cached) / memory.total
  185. return prettyNVRAM(usage)
  186. }
  187. return function (stream) {
  188. var children = []
  189. var el = document.createElement("div")
  190. var table = document.createElement("table")
  191. children.push(mkRow(table, "Laufzeit", stream.map(".uptime").map(prettyUptime)))
  192. children.push(mkRow(table, "Systemlast", stream.map(".loadavg").map(prettyLoad)))
  193. children.push(mkRow(table, "RAM", stream.map(".memory").map(prettyRAM)))
  194. children.push(mkRow(table, "NVRAM", stream.map(".rootfs_usage").map(prettyNVRAM)))
  195. children.push(mkRow(table, "Gateway", stream.map(".gateway")))
  196. children.push(mkRow(table, "Clients", stream.map(".clients.total")))
  197. el.appendChild(table)
  198. var h = document.createElement("h3")
  199. h.textContent = "Traffic"
  200. el.appendChild(h)
  201. table = document.createElement("table")
  202. mkTrafficRow(table, children, "Gesendet", stream, ".traffic.tx")
  203. mkTrafficRow(table, children, "Empfangen", stream, ".traffic.rx")
  204. mkTrafficRow(table, children, "Weitergeleitet", stream, ".traffic.forward")
  205. el.appendChild(table)
  206. children.push(mkMeshVPN(el, stream.map(".mesh_vpn")))
  207. function destroy() {
  208. children.forEach(function (d) {d.destroy()})
  209. }
  210. return { title: document.createTextNode("Statistik")
  211. , render: function (d) { d.appendChild(el) }
  212. , destroy: destroy
  213. }
  214. }
  215. })